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
Eight real suites. Compared test by test first.
click, flask, cachetools, anyio and four packages of a 10,000-test monorepo, run by pytest and by tiderace in the same virtualenv. Outcomes identical on seven of the eight, node id for node id, before a single timing is taken. Then wall clock — against serial pytest and against pytest -n auto, medians of interleaved rounds. The 5,600-test suite below is the honest one: both runners parallel, five thousand real tests.
Method: pinned corpora, one virtualenv per suite for both runners, parity by node id before speed, interleaved rounds with the load average recorded on every sample, medians. Numbers from the 29 September 2026 pass on the internal monorepo's pirn-core (5,036 tests); the other seven suites, the second-run table and every caveat are in the guide. Read 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.