Runtime State Isolation
When a mock endpoint uses persist = true, apitwin mutates stub files on disk. Without isolation, those mutations land in the same committed stubs/ directory your team tracks in git, dirtying git status after every session and risking accidental pushes of test data.
apitwin solves this by mirroring the seed stub tree into a gitignored runtime directory on startup. All reads and writes during a session go through the mirror, so the committed seed files are never touched.
How it works
- On startup, apitwin copies the entire config-dir tree (minus top-level config files and
.apitwin/itself) into.apitwin/state/next to the config. - Every stub read and write is redirected to the runtime mirror.
- On the next restart, the mirror is wiped and re-created from the seed, giving a clean slate.
.apitwin/state/is automatically added to the project's.gitignoreby--initandgenerate.
my-project/
├── apitwin.toml # committed config (seed)
├── stubs/
│ └── users/
│ ├── 1.json # committed seed stub (never mutated at runtime)
│ └── 2.json
├── .apitwin/
│ └── state/ # gitignored runtime mirror
│ └── stubs/
│ └── users/
│ ├── 1.json # runtime copy (mutations land here)
│ ├── 2.json
│ └── <uuid>.json # new record from POST — only exists in mirror
└── .gitignore # includes .apitwin/state/Modes
Default (runtime mirror)
apitwin --config ./my-projectCreates .apitwin/state/ next to the config. Mutations go there. Restart = fresh mirror from seed. This is the default — no flags needed.
Ephemeral
apitwin --config ./my-project --ephemeralThe mirror lives in a system tempdir instead of next to the config. Nothing is written to your project directory at all. The tempdir is removed on shutdown. Useful for CI, demos, and one-shot tests.
Legacy (no runtime dir)
apitwin --config ./my-project --no-runtime-dirDisables the mirror entirely. Mutations write back to the seed stubs, exactly like versions prior to v0.2.0-beta.15. Use this for scripts or test harnesses that write directly to stubs/ and assert against the same paths.
Resetting state
A restart always wipes and re-mirrors, so restarting the server is the easiest way to get back to seed state.
If you want to reset without restarting:
apitwin reset
apitwin reset --config ./my-projectThis deletes .apitwin/state/ so the next run starts fresh.
Record mode
When using --record, recorded stubs are dual-written: the canonical copy goes to the seed directory (so you can commit it) and a working copy goes to the runtime mirror (so the just-injected route serves it immediately during the current session).
Gitignore
--init, generate, and the server startup all ensure .apitwin/state/ is listed in the project's .gitignore. If the line is missing, the server logs a one-time warning on startup.
See also: Directory-Based Stubs | CLI Reference