Configuration
The sootsim.config.ts surface — module / turboModule / nativeModule resolution, env injection, settings, initialState — with real demo-app examples (Uniswap, Bluesky, Mattermost) and how the config currently reaches the runtime.
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.
Scaffold one
terminal
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.
Real demo-app examples
Uniswap — simple noop list
/Users/n8/github/uniswap-interface/sootsim.config.ts:
Bluesky — env only, CJS form
/Users/n8/github/bluesky/sootsim.config.js:
Mattermost — nativeModules + deep inline override
Mattermost reads its server config from dist/assets/config.json inside its
own bundle, and ships several legacy NativeModules:
See packages/sootsim/scripts/demo-app-registry.ts for the full Mattermost
entry. The same registry has entries for Expensify, Artsy, Joplin, and
Rainbow that exercise other parts of the surface.
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 — 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 currently reaches the runtime
The runtime config is carried as the ?sootsimConfig=<json> URL query
param. applySootSimConfigToUrl(url, config) writes it;
readSootSimConfigFromSearchParams reads it back inside the engine; the
engine then preloads { file: '…' } modules through the
/__sootsim-replacement-module dev-server endpoint and registers
inline/turbo/native overrides before any guest module factory runs.
Today the entry points that produce that URL are:
- The demo-app registry (
packages/sootsim/scripts/demo-app-registry.ts) attaches a hardcodedruntimeConfigper known demo (Mattermost, Expensify, Artsy, …). The dev-server scanner wraps the bundle URL withwithRuntimeConfigandsootsim open <port>opens that URL. - The
sootsim open --replace <module>=<file>CLI flag injects a one-off file override without touching a config file. - Programmatic callers of
applySootSimConfigToUrl(e.g. the electron host or custom scripts) can build the URL themselves.
A project’s on-disk sootsim.config.ts for a non-registry app is, today,
read by sootsim config show/validate but is not auto-loaded by
sootsim open or the Metro/One plugins — wire it up either by adding the
project to the demo registry, by passing --replace flags, or by calling
applySootSimConfigToUrl from your own launcher. The file format is the
forward-compatible target for auto-load.
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-15, …, iphone-16-pro-max | iphone-15-pro |
| orientation | --orientation | portrait, landscape | portrait |
Appearance
| setting | CLI flag | values | default |
|---|---|---|---|
| colorScheme | --theme | light, dark, auto | light |
| reduceMotion | — | boolean | false |
| boldText | — | boolean | false |
| fontSize | — | 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 | — | boolean | false |
| showStatusBar | — | boolean | true |
| showHomeIndicator | — | boolean | true |
| a11yMode | — | off, default, always | default |
| inspectMode | — | 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 — Expo, bare React Native, any Metro app
- One Plugin — One apps
These integrations expose SootSim on the existing dev server but do not
auto-load sootsim.config.ts — see “How the config currently reaches the
runtime” above.