[ Documentation ]
PeachConfig

PeachConfig

The main configuration object for Peach projects. Import from peachsim/config:

import { defineConfig } from 'peachsim/config'
export default defineConfig({
modules: { ... },
turboModules: { ... },
nativeModules: { ... },
nativeViews: { ... },
env: { ... },
settings: { ... },
initialState: { ... },
})

defineConfig is a typed pass-through; the file may also be plain CJS:

/** @type {import('peachsim/config').PeachConfig} */
module.exports = { env: { ... } }

Module slots

There are four separate slots because the runtime resolves each differently.

modules

Record<string, ModuleResolution>: overrides for any Metro module by path fragment. The key is matched against the Metro module name as a path fragment, not a strict package name. A key like react-native-widgetkit matches …/node_modules/react-native-widgetkit/index.js; a key like dist/assets/config.json matches a deep file path inside a module.

Keys are sorted longest-first, so subpath keys can override package-level keys.

turboModules

Record<string, NativeModuleResolution>: modules served via the TurboModuleRegistry surface. Keyed by the TurboModule name the guest bundle requests (e.g. RNCAsyncStorage), not by JS module path.

nativeModules

Record<string, NativeModuleResolution>: modules served via the legacy NativeModules surface and Expo’s requireNativeModule. Keyed by the native module name the guest bundle requests (e.g. RNKeychainManager, or an Expo module’s Name).

Replacement files may use the kit primitives through their family subpaths.

nativeViews

Record<string, NativeViewResolution>: the app’s own native views, each replaced by a React component. Keyed by the native view name the guest bundle asks for:

the app callskey
requireNativeComponent('RNBalanceLabel')RNBalanceLabel
requireNativeView('MyModule', 'ProgressiveBlurView')MyModule_ProgressiveBlurView
requireNativeView('MyModule')MyModule
type NativeViewResolution = 'noop' | { file: string }

'noop' renders an empty view. A replacement file default-exports the component. It receives exactly the props the app passes to the native view, and may import react, react-native, peach-kit and the packages Peach bridges for the app. A name with no entry keeps Peach’s behavior: its built-in implementation, else an empty view.

See Native View Primitives for a typed progressive-blur replacement.

Module resolution kinds

type ModuleResolution =
| 'noop' // stub as an empty module
| false // disable peach's builtin stub, use the original
| { use: string } // redirect to an existing compat stub by name
| { file: string } // resolve to a project-local file
| { inline: Record<string, any> } // inline static object as the module exports

turboModules and nativeModules additionally accept a direct native-module object (any shape) for non-URL configs:

type NativeModuleResolution = ModuleResolution | Record<string, any>

env

Record<string, string>: environment variables installed as process.env.* inside the guest runtime.

Caveat: many React Native projects read env vars at bundle time via Babel plugins (react-native-dotenv, Expo’s EXPO_PUBLIC_* inliner, …). Those values are already baked into the bundle that Metro served. env here only sets process.env.* for code that reads env at runtime; code that already got its values inlined at bundle time will not see new values. To change those, rebuild the bundle with the new env and reload.

settings

Partial<SettingsValues>: simulator settings overrides (device model, appearance, network, locale, chrome). See settings schema.

initialState

Initial app state passed to the simulator:

{
authenticated?: boolean
locale?: string
colorScheme?: 'light' | 'dark' | 'auto'
featureFlags?: Record<string, boolean | string | number>
[key: string]: any
}

How the config reaches the runtime

The config travels as the ?peachConfig=<json> URL query param.

  • +
    applyPeachConfigToUrl(url, config) serializes into the param.
  • +
    readPeachConfigFromSearchParams(searchParams) deserializes inside the engine.
  • +
    The engine preloads any { file: '…' } modules by fetching them through the /__sootsim-replacement-module dev-server middleware (one project-local source file, whose imports are restricted to react, react-native, and the packages the simulator bridges for this app).
  • +
    The bundle loader matches modules keys against every __d() factory registration and serves the configured resolution instead.

mergePeachConfig(base, override) shallowly merges two configs by slot.