Understanding System Bundles for Vega Apps
Modern apps built on React Native often ship with large monolithic JavaScript bundles. These bundles include everything, from core React libraries to app-specific business logic. However, this approach creates challenges: bigger app sizes, slower startup, and more friction when delivering bug fixes.
Vega introduces a split bundle system, where common libraries live on the system and apps only ship the code that's unique to them. This article explores what this means, why it matters, and how it works.
About split bundles
Traditionally, a React Native app ships a single app bundle containing:
- Core libraries like
reactandreact-native - Vega-specific modules
- Third-party libraries
- Your app's code
With split bundles, the app bundle is divided into two parts:
System (common) bundle
Preinstalled on the device, this bundle contains widely used libraries such as react, react-native, and @amazon-devices/react-native-kepler. For details, see system distributed libraries. The system bundle is kept in sync with the native Vega runtime.
Split app bundle
Your app's bundle, minus the common libraries. This contains only app-specific code and any unique dependencies.
How the transformation works
Below is a simplified view of how a monolithic bundle is split:
┌────────────────────────────┐
│ Monolithic App Bundle │
│ (React, RN, Vega, App) │
└────────────────────────────┘
│
▼
┌────────────────────┐ ┌─────────────────────┐
│ System Bundle │ │ Split App Bundle │
│ (React, RN, Vega) │ │ (App-specific code) │
└────────────────────┘ └─────────────────────┘
At runtime, Vega loads the system bundle first, then stitches in your split app bundle.
Why split bundles matter
Split bundles bring several key advantages:
- Smaller app size – Removing common libraries from your app bundle reduces its size by 1MB or more.
- Faster startup times (TTFD) – Core libraries are preloaded on the device, reducing app initialization time by ~100–150ms.
- Automatic bug fixes – Since system libraries update independently, your apps get bug fixes and performance improvements without requiring a new app release.
- Reduced compatibility issues – Both JS and native components live in the same system version, ensuring compatibility.
How the split bundle system works
Behind the scenes, the split bundle system relies on extending Metro, the JavaScript bundler used by React Native. Normally, Metro produces a single index.bundle with all your app's code and dependencies. To enable splitting, Vega customizes Metro's Serializer stage, which controls how modules are combined into bundles.
Two, key hooks make this possible:
processModuleFilter
- Filters out modules already provided by the system bundle.
- Ensures that app bundles don't duplicate libraries like
reactorreact-native.
createModuleIdFactory
- Assigns consistent, deterministic IDs to modules, ensuring that system and app bundles reference the same module IDs when sharing code.
- Instead of Metro's default incremental IDs, Vega uses a hash-based scheme, such as SHA-256 of the module path, to guarantee stability across builds.
Build time Runtime
──────────────────► ───────────────►
┌─────────────┐ ┌──────────────┐ uses IDs in ┌───────────────┐
│ Source │─► │ Core Bundle │───────────────► │ Load Core │
│ (app + lib) │ │ (React, RN, │ │ (system) │
└─────────────┘ │ Vega) │ └───────────────┘
└─────┬────────┘
│ writes modules.txt
▼
┌──────────────┐ uses IDs in ┌───────────────┐
│ Library Bndl │───────────────► │ Load Libraries│
│ (e.g. RNScrn)│ │ (system) │
└─────┬────────┘ └───────────────┘
│ reuses IDs / filters
▼
┌──────────────┐ ┌───────────────┐
│ App Bundle │───────────────► │ Load App │
│ (split) │ │ (on top) │
└──────────────┘ └───────────────┘
Types of bundles
The split bundle system creates three main bundle types:
Core bundles (system)
- Contains fundamental libraries (
react,react-native,@amazon-devices/react-native-kepler). - Generated first, producing a
modules.txtfile mapping module paths to IDs. - This mapping ensures consistent referencing in dependent bundles.
Library bundles (system)
- For popular libraries like
react-native-reanimatedorreact-native-screens. - Created using the
modules.txtfrom the core bundle to avoid duplicating already-bundled dependencies. - Additional
modules.txtfiles are generated for each library.
Application bundles (split app bundle)
- Your app's code is filtered to exclude anything already included in system bundles.
- References system-provided modules through the shared IDs.
At build time, metadata such as keplerscript-app-system-bundles-config.json is generated, telling Vega which system bundles your app requires. At runtime, the Vega runtime first loads the system bundles, then attaches the app bundle on top.
Handling dependencies and versions
A major challenge in split bundling is dependency versioning:
- If the system bundle has
react-native-screens@2.0.0, but your app requires2.1.0, conflicts can arise. - To manage conflicts, Vega uses versioned module paths internally, such as
react-native-screens__2/. - Only major versions are encoded into paths, such as
__2/, so bugfix upgrades from2.0.0to2.0.1don't break compatibility or force app rebuilds.
When filtering dependencies:
System bundles include their own dependencies, such as lodash, but don't list them in modules.txt. Therefore, if an app depends on the same version of lodash, it's still present in the app bundle, preventing accidental breakages when system libraries upgrade.
Same major, safe upgrade:
@amzn/react-native-screens__2/... (2.0.0 → 2.0.1 keeps the same path)
Different major, intentionally distinct:
@amzn/react-native-screens__3/...
This approach, combined with stable IDs, lets the system update frequently while apps remain compatible.
Lifecycle of a system bundle build
Here's the full lifecycle of a split bundle build:
- Core bundle is created – Contains React, React Native, and Vega modules.
- Library bundles are created – Uses dependency-aware filtering based on the core bundle's
modules.txt. - App bundle is created – All system-provided modules are removed.
- Metadata is generated – Lists which system bundles are required by the app.
- Vega loads – System bundles first, then the app bundle.
The result is a modular system where apps stay small, fast, and resilient to library updates.
Related topics
- React Native for Vega App Architecture – Covers the broader architectural decisions behind Vega, including how the React Native runtime is built into the OS and dynamically linked with apps.
- Supported Libraries and Services – Lists all system distributed libraries that ship as part of the system bundle, along with their versions and compatibility details.
- Import Libraries in Your App with VMRP – Explains how to configure module resolution for split bundling, which doesn't support standard npm aliases and overrides.
- App Performance Best Practices – Provides additional techniques for reducing bundle size and improving startup time beyond what system bundles handle automatically.
- Install and Configure the Vega ESLint Plugin – Includes lint rules that validate system distributed library usage in your
package.jsonand flag imports that behave differently under split bundling.
Last updated: Apr 16, 2026

