as

Settings
Sign out
Notifications
Alexa
Amazonアプリストア
Ring
AWS
ドキュメント
Support
Contact Us
My Cases
開発
設計と開発
公開
リファレンス
サポート
アクセスいただきありがとうございます。こちらのページは現在英語のみのご用意となっております。順次日本語化を進めてまいりますので、ご理解のほどよろしくお願いいたします。

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 react and react-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 react or react-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.txt file mapping module paths to IDs.
  • This mapping ensures consistent referencing in dependent bundles.

Library bundles (system)

  • For popular libraries like react-native-reanimated or react-native-screens.
  • Created using the modules.txt from the core bundle to avoid duplicating already-bundled dependencies.
  • Additional modules.txt files 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 requires 2.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 from 2.0.0 to 2.0.1 don'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:

  1. Core bundle is created – Contains React, React Native, and Vega modules.
  2. Library bundles are created – Uses dependency-aware filtering based on the core bundle's modules.txt.
  3. App bundle is created – All system-provided modules are removed.
  4. Metadata is generated – Lists which system bundles are required by the app.
  5. 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.


Last updated: Apr 16, 2026