Your tests, forced through the fastest water.
A tide race is where the sea is squeezed through a narrow channel and accelerates into the fastest navigable current on the coast. tiderace does that to your test suite: collection, fixtures, scheduling, isolation, coverage and impact analysis all live in compiled Rust. A tiny Python shim only imports your tests and calls their bodies. Your suite stops being a tax.
Ships as tiderace (one-shot) & tiderace-daemon (warm server)
The boldest thing a test runner can do
Watch what doesn't run.
tiderace records a per-test source footprint with CPython sys.monitoring and content-hashes everything it touches. Change one file and only the tests that actually depend on it re-run. Change nothing and the interpreter is never even launched. Touch a file below.
Touch a file. See the ripple.
edit one of these
Nothing changed. Nothing runs — the interpreter isn't even launched.
Why it's actually fast — not a trick
Pay for isolation only where a test needs it.
Fork-per-test is the tax everyone quietly pays. tiderace classifies each test and runs it the cheapest sound way. Most tests never touch global state — so most tests never pay.
In-process, no fork
Deterministic tests that don't mutate shared state run straight in the interpreter. No process spawn, no page-table copy, no teardown.
In-process, snapshot & restore
State-mutating tests get a captured snapshot of module globals and os.environ, then a restore afterward — isolation without a whole new process.
Forked — only when it must be
The genuinely un-snapshotable cases still fork for full isolation. Correctness first; you just don't pay for it everywhere.
Sound by construction: a module that can't be snapshotted always falls back to fork. On Windows there's no fork() — so an opt-in sub-interpreter tier (CPython 3.14+, PEP 684 per-interpreter GIL) delivers parallel, no-fork execution there too.
The numbers, measured — not vibes
509 fixture tests. hyperfine. numpy & sqlite.
The corpus is real (fx_corpus), the tool is hyperfine, the comparison is honest — including the run where tiderace only wins 1.4×.
Method: fx_corpus (509 fixture tests, numpy/sqlite), measured with hyperfine. tiderace runs its own engine — collection, fixture graph, scheduling, hashing and impact analysis are all native Rust. There is no pytest in the loop at runtime. Reproduce the benchmarks →
The engine room
A build system, aimed at your tests.
Not a pytest plugin. Not a wrapper. tiderace owns the whole pipeline in compiled Rust and treats a test outcome like a build artifact — content-addressed, cacheable, portable.
Content-addressed outcomes
A result computed in CI is reusable on any machine. An unchanged test is free — you don't recompute what you already know. This is a build cache for correctness.
Impact analysis, natively
Per-test footprints via sys.monitoring plus content hashing. No change means nothing runs — the interpreter isn't launched at all.
Windows-first parallelism
No fork()? No problem. An opt-in sub-interpreter tier on CPython 3.14+ (PEP 684 per-interpreter GIL) runs no-fork isolation in parallel — on Windows too.
Rust owns the pipeline
Collection, the fixture graph, scheduling, hashing and impact analysis run at native speed. The Python side is a shim that imports tests and calls their bodies. That's it.
Migrate off pytest with one command
The tiderace migrate codemod auto-maps the vast majority of real suites — so you're not rewriting tests by hand to try it. Read the migration guide →
Stop paying the test tax.
Point tiderace at your suite, run the codemod, and let the current do the work. Unchanged tests are free — everywhere, on every machine.