Configuration
sootsim.config.ts (or .js) is the per-project, repo-rooted config file
that describes how SootSim should load your app: which native modules to
stub, which env vars to inject, which device/appearance settings to default
to, and any initial app state.
Create one
Create sootsim.config.ts in the repo root only when you need advanced module,
environment, or simulator overrides. It is not required for normal
sootsim open <port> usage.
Both forms are accepted:
Full reference
How module / turboModule / nativeModule differ
Three separate slots because the runtime resolves each differently:
modules: overrides for any Metro module by path fragment. Keys are matched against the Metro module name (e.g.…/node_modules/react-native-widgetkit/index.js); a key likereact-native-widgetkitmatches that path. Keys are tried longest-first, so subpath keys override package-level keys.turboModules: keyed by the TurboModule name the guest bundle requests (RNCAsyncStorage,RNFastImageView, …), served through SootSim’s TurboModuleRegistry surface.nativeModules: keyed by the legacy NativeModules name (RNKeychainManager,RNUtils, …), served through theNativeModules.<Name>surface.
If a guest bundle reads TurboModuleRegistry.get('Foo') and you have a
Foo key under modules, it will not match: modules is for JS-module
paths, turboModules is for TurboModule names.
ModuleResolution kinds
turboModules and nativeModules additionally accept a direct
Record<string, any> for non-URL configs.
Examples
Simple noop list
Silence native modules that are irrelevant in the simulator (analytics, IDFA, widgets, in-app updates):
Env only, CJS form
nativeModules + deep inline override
Some apps read config from a JSON file deep inside their own bundle and ship several legacy NativeModules. You can override a deep file by path fragment and seam the native managers:
The three slots compose freely: redirect JS modules by path, seam TurboModules and legacy NativeModules by name, and inline static config a package reads from its own bundle.
Env caveat: bundle-time vs runtime
Many React Native projects read env vars at bundle time via Babel plugins
(react-native-dotenv, Expo’s EXPO_PUBLIC_* inliner, babel-plugin-transform-inline-environment-variables).
Those values are already inlined into the bundle Metro served, so env in
sootsim.config.ts only sets process.env.* for code that reads env at
runtime.
If your code looks like process.env.API_URL after Metro and that string
has been replaced by a literal in the bundle, changing env here does
nothing. Rebuild the bundle with the new env (restart Metro with the new
.env, or set the var in the Metro process) and reload. Bluesky and
Uniswap’s configs both document this constraint.
How the config reaches the runtime
The CLI carries your config to the engine when it opens your app, and the engine applies the module / turbo / native overrides before any guest module factory runs. Env vars that were already inlined at bundle time can’t be changed here (see the caveat above).
For a one-off module swap without writing a config file, pass it inline:
terminal
sootsim maestro test accepts the same --replace <module>=<file> flag, so a test run
can stub a module for just that run.
Settings reference
Settings can be configured three ways, in order of override priority (highest last):
sootsim.config.ts: project-level defaults- Simulator UI: runtime changes (notification center pull-down)
- CLI flags: per-invocation overrides
Device
| setting | CLI flag | values | default |
|---|---|---|---|
| deviceModel | --device | iphone-se, iphone-16, …, iphone-17-pro-max | iphone-17-pro |
| orientation | --orientation | portrait, landscape | portrait |
Appearance
| setting | CLI flag | values | default |
|---|---|---|---|
| colorScheme | --theme | light, dark, auto | auto |
| reduceMotion | none | boolean | false |
| boldText | none | boolean | false |
| fontSize | none | 0.5–2.0 | 1.0 |
Network
| setting | CLI flag | values | default |
|---|---|---|---|
| networkCondition | --network | wifi, lte, fast-3g, slow-3g, offline | wifi |
Locale
| setting | CLI flag | values | default |
|---|---|---|---|
| language | --language | ISO 639-1 codes | en |
| region | --region | ISO 3166-1 codes | US |
Chrome
| setting | CLI flag | values | default |
|---|---|---|---|
| showFrame | --frame | boolean | true |
| showTouches | none | boolean | false |
| showStatusBar | none | boolean | true |
| showHomeIndicator | none | boolean | true |
| a11yMode | none | off, delayed, active | delayed |
| inspectMode | none | boolean | false |
Optional dev-server integration
If you want a stable /__soot URL on the same dev server your team already
runs, install the integration that matches your stack:
- Metro Plugin for Expo, bare React Native, and any Metro app
- One Plugin for One apps
These integrations expose SootSim on the existing dev server but do not
auto-load sootsim.config.ts, so apply module overrides with --replace (see
“How the config reaches the runtime” above) when driving through a plugin.
