Skip to content

Repository files navigation

react-native-bundle-discovery

npm version npm downloads license

Visualize and analyze the JS bundle of your React Native app. Find heavy packages, duplicates and deprecated dependencies, inspect every module, and catch bundle size regressions in CI.

Bundle Discovery UI

Contents

Features

  • πŸ“Š Interactive UI to explore packages, modules and their source/bundled code
  • πŸ’‘ Optimization recommendations (duplicates, deprecated / outdated / dev-only packages, and more)
  • πŸ” CLI to list the heaviest packages and modules
  • πŸ†š Compare two reports and fail CI on bundle size regressions
  • 🧩 Works with Metro, Re.Pack and React Native DevTools (via Rozenite)

Packages

Package What it does Required
react-native-bundle-discovery Generates a JSON report (metro-stats.json) of your bundle βœ… Yes
react-native-bundle-discovery-ui Shows the report in the browser Optional
react-native-bundle-discovery-cli Analyzes and compares reports in the terminal / CI Optional
react-native-bundle-discovery-rozenite-plugin Shows the UI inside React Native DevTools Optional

Quick start

This setup is for a standard Metro project. Using Re.Pack or Rozenite? See Other setups.

Tip

Using an AI coding agent? Skip the manual steps below. Point your agent (Claude Code, Cursor, Codex, etc.) at the setup-react-native-bundle-discovery skill. It installs the package and sets up Metro or Re.Pack for you:

npx skills add retyui/react-native-bundle-discovery

1. Install

yarn add -D react-native-bundle-discovery      # required: generates the report
yarn add -D react-native-bundle-discovery-ui   # optional: browser UI
yarn add -D react-native-bundle-discovery-cli  # optional: CLI

2. Configure Metro

// metro.config.js
const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config');
+const { createSerializer } = require('react-native-bundle-discovery');

-const config = {};
+const config = {
+  serializer: {
+    customSerializer: createSerializer({
+      projectRoot: __dirname, // ⚠️ In a monorepo, use the monorepo root instead
+    }),
+  },
+};

module.exports = mergeConfig(getDefaultConfig(__dirname), config);

See all options in createSerializer.

3. Build a release bundle

npx react-native bundle \
  --entry-file index.js \
  --platform ios \
  --dev false \
  --bundle-output ios/main.jsbundle \
  --assets-dest ios/assets

This writes metro-stats.json to your project root.

4. Explore the report

npx react-native-bundle-discovery-ui metro-stats.json   # open in the browser
npx react-native-bundle-discovery-cli metro-stats.json  # get recommendations in the terminal

Other setups

Setup Guide
Re.Pack (Rspack / Webpack) Re.Pack.md
React Native DevTools Rozenite plugin
AI coding agent Point your agent at the setup-react-native-bundle-discovery skill

Usage

UI

Requires react-native-bundle-discovery-ui.

# Start a local server (default port: 8079)
npx react-native-bundle-discovery-ui metro-stats.json [--port <port>]

# Build a static HTML report (default output: .bundle-discovery)
npx react-native-bundle-discovery-ui build metro-stats.json [--output <path>]

CLI

Requires react-native-bundle-discovery-cli. Run any command with --help to see all options.

Command Description
(none) Show recommended optimizations for the bundle
packages List all packages in the bundle
modules List the heaviest modules
compare Compare two reports
# Recommended optimizations
npx react-native-bundle-discovery-cli metro-stats.json

# All packages
npx react-native-bundle-discovery-cli packages metro-stats.json [--sort size|name] [--format json|table|default]

# Heaviest modules (default --limit: 50, use 0 to show all)
# --filter accepts plain text (case-insensitive) or a regexp, e.g. --filter '/\.json/i'
npx react-native-bundle-discovery-cli modules metro-stats.json [--limit 50] [--filter <text|/regexp/>] [--sort size|name] [--format json|table|default]

# Diff two reports: total size, added/removed/changed modules and packages,
# version changes, new duplicates and new deprecated packages
npx react-native-bundle-discovery-cli compare --before main-stats.json --after pr-stats.json [--limit 50] [--format json|markdown|default]

Bundle size checks in CI

compare exits with code 1 when any check fails:

Option Fails when Example
--fail-on-increase The bundle grows more than the limit (bytes or % of "before") 50KB, 0.5MB, 51200, 5%
--max-size The "after" bundle is bigger than the limit 3MB
--fail-on New duplicate and/or deprecated packages appear new-duplicates,new-deprecated
npx react-native-bundle-discovery-cli compare --before main-stats.json --after pr-stats.json \
  --fail-on-increase 50KB \
  --max-size 3MB \
  --fail-on new-duplicates,new-deprecated

GitHub Actions works out of the box: the markdown report is added to the job summary and failed checks are shown as error annotations.

- run: npx react-native-bundle-discovery-cli compare --before main-stats.json --after pr-stats.json --fail-on-increase 5%

To post the report as a PR comment, use --format markdown.

API

Exported from react-native-bundle-discovery.

createSerializer(options)

Creates a Metro serializer that writes the JSON report. Use it as serializer.customSerializer (see Quick start).

Option Type Default Description
projectRoot string Required Project root. ⚠️ In a monorepo, use the monorepo root, not the app package directory.
outputJsonPath string <projectRoot>/metro-stats.json Where to save the report.
includeCode boolean true Include source and bundled code of each module in the report (larger file).
includeEnvs string[] [] Names of environment variables to include in the report.
fetchPackagesMetadata boolean true Fetch package metadata (publish date, deprecation, latest version) from the npm registry.
silent boolean false Disable log output.
serializer Function Metro default serializer Custom serializer to wrap.

Warning

With includeCode: true (the default) the report contains your source code. If your code is proprietary, be careful who you share the report with.

createResolveRequest(options)

Creates a Metro resolveRequest that removes unnecessary React Native modules from release bundles (dev builds are not affected). The CLI recommends these options when they apply to your bundle.

Option Type Default Description
removeUTFSequence boolean false Remove the unused react-native/Libraries/UTFSequence.js module.
removeNewRenderer boolean false Remove the Fabric renderer. Enable only if the New Architecture is disabled.
// metro.config.js
const { createResolveRequest } = require("react-native-bundle-discovery");

const config = {
  resolver: {
    resolveRequest: createResolveRequest({
      removeUTFSequence: true,
    }),
  },
};

Similar projects

Built with Discovery.js (views showcase, Jora syntax).

Support the project

Become a financial contributor on OpenCollective or GitHub Sponsors.

License

MIT

About

Simple tooling to explore bundle size πŸ“¦, spot heavy packages, and inspect module/code structure in React Native apps.

Topics

Resources

Contributing

Stars

152 stars

Watchers

1 watching

Forks

Releases

Sponsor this project

Contributors

Languages