DEV Community

Mohammed Arshad Ansari
Mohammed Arshad Ansari

Posted on Originally published at hikmahtechnologies.com

Is DuckDB safe for production? The honest limitations

"Is DuckDB safe for production?" is the right question asked slightly wrong. DuckDB is not a scaled-down toy that becomes safe once you're brave enough. It's a database with a specific concurrency and durability model, and it is completely safe inside that model and genuinely unsafe outside it.

So the useful version of the question is: safe for which workload? Here's what actually bites, in the order it bites people.

The single-writer model is the whole story

DuckDB allows one writing process at a time against a database file. Multiple threads inside that process are fine. Many processes can read the file at once, as long as none of them is writing. Two processes both opening the file for writing are not.

This is not a bug or a temporary limitation — it's the design. DuckDB is an in-process database, like SQLite. There is no server arbitrating between clients, because there is no server.

Almost every "DuckDB isn't production-ready" story I've heard traces back to this. Someone runs the ETL job on a schedule, someone else points a dashboard at the same file, and eventually the two overlap. What you get is a lock error, or — if you were clever enough to copy the file to dodge the lock — a reader seeing a half-written state.

The design that avoids it entirely:

                    ┌─ writer job ──► Parquet partitions on S3
                    │                   (immutable, append-only)
  source systems ───┤
                    └─ readers ────► DuckDB, N processes, read-only
Enter fullscreen mode Exit fullscreen mode

Writers never share a mutable file. They produce immutable Parquet partitions. Readers open those partitions read-only, as many processes as you like, with no coordination at all. The concurrency problem disappears because you removed the shared mutable state, not because you managed it better.

If you must use a .duckdb file with concurrent readers, open them explicitly read-only:

import duckdb

# Safe: many of these can run at once against the same file.
con = duckdb.connect("analytics.duckdb", read_only=True)
Enter fullscreen mode Exit fullscreen mode

Read-only processes share the file with each other but not with a writer: while any process holds it read-write, the others cannot open it at all. That is why the writer should produce Parquet rather than update the file the readers use. DuckDB will also refuse a write through a read-only connection rather than corrupt anything.

Durability: it's ACID, but know what that covers

DuckDB is ACID-compliant with write-ahead logging. A transaction that commits is durable; a crash mid-transaction rolls back cleanly. On this axis it behaves like a real database, because it is one.

What people actually get wrong is what sits around the transaction:

  • The file is a single point of failure. ACID protects you from a crash. It doesn't protect you from a deleted file, a corrupted volume, or an ephemeral container's disk vanishing at the end of the run. If your database lives on a pod's local disk, it lives exactly as long as the pod.
  • A .duckdb file is not a backup format. Copying it while a writer is mid-transaction gives you a file whose contents are undefined. Snapshot by exporting (EXPORT DATABASE) or by treating Parquet as the durable layer.
  • Storage format compatibility. DuckDB reached 1.0 with a stability commitment, and files are forward-compatible within that line — but a file written by a newer version isn't necessarily readable by an older one. Pin the version in production and upgrade deliberately, the same as any database.

The rule I use: Parquet is the durable artefact, the .duckdb file is a cache. If losing the file would be a data-loss incident rather than an inconvenience, the architecture is wrong, not DuckDB.


This is the first part. The full post — including the rest of the working details — is on my site: Is DuckDB safe for production? The honest limitations

Top comments (0)