Flintstack › FAQ
Frequently asked questions
Collected from the mailing address, lightly edited. If your question is not here, it is probably in the CLI reference or worth an email.
Which compilers are supported?
Anything that behaves like a C or C++ compiler driver on the command line: takes
-c, writes one output file, and can be asked for its dependency list. We test
against two mainstream drivers and one cross-compiler on every release. Other languages work
if their compiler has the same shape - people cache an assembler and a protocol-buffer
generator this way - but you will be the first to find the sharp edges.
We already use a compile cache. Why switch?
If what you have works, do not switch. The two reasons people give us are the shared tier
(one cache for a fleet of ephemeral runners, which single-machine caches do not address) and
the key being inspectable with flint key --explain when a miss makes no sense.
Neither is worth a migration on its own.
Yes, and it is the normal arrangement. Keys are derived from inputs, so two projects simply
do not collide unless they are compiling identical files with identical flags - in which case
sharing the result is correct and desirable. What they do share is the eviction budget:
a noisy project can push a quiet one out of an undersized store, which is an argument for
raising max_size rather than for splitting.
The hit rate stays at zero. What now?
Run flint key --explain on the same compile twice, in two separate shells,
and diff the two outputs. In order of frequency, the cause is: an absolute path in the
argument vector that normalization did not catch; a variable like a job id that somebody added
to env_allow; a generated header rewritten on every run so its digest changes;
or the daemon not actually running, which flint doctor says in one line.
Does it cache failed compiles?
No, and this is deliberate. A failure depends on things we do not hash - the state of a generated file somewhere else in the tree, the locale, how much disk was left. Returning a stored failure would turn a transient break into a sticky one, and the time saved by not re-running a compiler that fails in 200 ms is not worth that.
What happens when the disk fills up?
Eviction normally keeps the store under max_size, but if the filesystem
itself runs out - because something else on the box ate the space - writes start failing.
The daemon logs at warning level, counts the failures, serves reads normally, and keeps
builds working. It will not delete beyond its own policy to rescue a filesystem it does
not own.
Is it useful on a single developer machine?
Modestly. Your local build tool already avoids recompiling what has not changed; the cache
earns its place when you switch branches, when you rebuild after a clean, and when you can
read from a shared tier that CI fills. For that last case run with
--no-store and read_only = true: consume the fleet's cache,
contribute nothing, stay out of everyone's eviction budget.
Should I back up the store?
There is no reason to. Every entry is reproducible by definition - that is what makes it cacheable - and a restored store is stale the moment the toolchain moves. Back up the configuration file instead, which is the only part you cannot regenerate in a minute.
Will there be a Windows port?
Not from us. The store relies on atomic rename within a filesystem, advisory locks with POSIX semantics, and the ability to unlink a file that is still open. The last one has no equivalent, and working around it means a different storage layer rather than a port. A fork is welcome to try; we will take patches that do not complicate the POSIX path.
How do I remove it cleanly?
Three steps, no residue:
sudo pkill -TERM flintd
sudo rm -rf /var/lib/flint /run/flint /etc/flint
sudo rm -f /usr/local/bin/flintd /usr/local/bin/flint
Then drop the wrapper from your build invocation. Nothing else was ever written: no kernel module, no package database entry, no cron job, and no outbound connection other than the backends you configured yourself.
Last updated: 2026-09-10