Home / FAQ
Questions before you swap the binary
Everything here reflects how rninja already works. For the mechanics, see how it works; for adoption, the quickstart.
[+] Is rninja really a drop-in replacement for ninja?
Yes — that is the design goal. rninja parses the same build.ninja format, accepts the same core flags (-C, -f, -j, -k, -l, -n, -t, -v, -d), preserves NINJA_STATUS, mirrors exit codes, and matches semantics for phony targets, depfiles, and restat. If a build works under ninja, it should work under rninja. Cache-specific options live behind RNINJA_* env vars so they cannot collide with stock ninja flags.
[+] Which flags and subtools does rninja support?
The core ninja flags: -C, -f, -j, -k, -l, -n, -t, -v, -d. The -t subtools clean, compdb, graph, deps, and query behave like ninja. rninja adds -t config for inspecting or generating an rninja.toml and a stats view for cache hit rate.
[+] What speedup should I expect?
On warm incremental builds with high cache reuse, roughly 2x to 5x, per the rninja docs. CI pipelines with a shared remote cache see a similar reduction in compute minutes after the first job warms the store. These ranges assume large C/C++-style repos where compile and link dominate. Measure your own repo with a side-by-side timing before relying on a number.
[+] How does the cache decide what is reusable?
Every action gets a content hash over its full inputs (source bytes, includes, generated headers), its command line, and the environment the rule observes. Identical inputs produce an identical hash, so a hit means a guaranteed-equivalent artifact. Non-deterministic outputs (embedded timestamps, random seeds) lower the hit rate; making them deterministic pays back immediately.
[+] Can caching mask a build bug or produce a wrong build?
Caching is strictly additive. A miss falls through to the original ninja action; a hit only happens when inputs, command, and environment all match. rninja’s drop-in compatibility is about producing the same artifacts ninja would — if anything diverges, that is a bug, and -d explain surfaces why an edge rebuilt.
[+] Do I need to run a server for the remote cache?
No. The remote cache is opt-in via RNINJA_REMOTE_URL and RNINJA_CACHE_MODE. async-nng handles the transport, so a single small endpoint can serve multiple machines. Leave it unset and rninja is a purely local cache plus scheduler; the local store always front-runs the remote.
[+] Which generators and platforms are supported?
Anything that emits a standard build.ninja — CMake, GN, Meson, and hand-written ninja files all work without modification. rninja does not regenerate the file; it executes it. It runs on Linux and macOS.
[+] How do I install rninja?
cargo install rninja, npm install -g rninja-cli, pip install rninja-cli, or brew install neul-labs/tap/rninja. Prebuilt binaries are on the GitHub Releases page. From source: cargo install --path . inside a clone.
[+] How is rninja different from sccache and ccache?
sccache and ccache are compiler caches: they wrap a single compiler invocation. rninja caches whole ninja actions, so it can skip an entire graph edge — not just the compile — and it adds an async scheduler and an optional remote cache. They coexist: you can run ccache inside an rninja action. See the comparisons for a full breakdown.
[+] Is rninja production-ready?
rninja is published on crates.io, npm, and PyPI, and is MIT licensed. It pays off best on repos that already feel slow under ninja. Run it side by side (time the ninja build vs the rninja build) on your own project before flipping it on in CI.