A “file database” almost always means one of two very different things: a flat file like a CSV or JSON blob with no query engine at all, or an embedded database like SQLite or DuckDB that speaks real SQL but still lives as a single file on disk — and the difference between the two, and between both and a client-server database, decides whether your app survives its next redeploy.
The term gets used loosely enough that two people can mean completely different things by it in the same conversation. The distinction is not academic: it is the difference between a design choice that is genuinely fine and one that quietly loses data the first time your hosting platform restarts the container.
Table of contents
- Flat file: no engine, just structured text
- File-based embedded databases: SQLite and DuckDB
- Client-server databases: the other model entirely
- When a file database is genuinely enough
- Why file databases break on ephemeral container filesystems
- When to move to managed Postgres or MySQL
- How this fits the rest of the stack
- FAQ
Flat file: no engine, just structured text
A flat file — a CSV, a JSON blob, a plain text log — is data with no query engine attached. Reading it means loading the whole thing and parsing it yourself; there is no index, no concurrent-safe write path, and no query language beyond whatever loop you write in your application code.
This is completely appropriate for configuration, small export/import jobs, and read-mostly reference data that changes rarely and is rebuilt wholesale rather than updated row by row. It stops being appropriate the moment two processes might write to it at the same time, because nothing enforces safety at that layer — you would have to build locking yourself, badly, on top of a format that was never designed for it.
File-based embedded databases: SQLite and DuckDB
SQLite is the step up from a flat file that still keeps everything in one file: a full relational engine, ACID transactions, real SQL, and zero separate server process. Your application opens the file directly and the SQLite library handles concurrency, indexing, and durability internally. SQLite vs PostgreSQL covers exactly where that model is the right call and where it stops being one.
DuckDB follows the same file-based embedded model — no server, one file, opened in-process — but is built for a different job: column-oriented analytical queries over large local datasets, often reading Parquet or CSV files directly rather than serving transactional application writes. Both are file databases in the literal sense; neither is a flat file, because both bring a real query engine with them.
Client-server databases: the other model entirely
Postgres and MySQL run as a separate server process that your application reaches over a network connection, even when that connection is to localhost. Multiple application instances connect to the same server concurrently, and the actual on-disk files are managed entirely by the database server — your application never touches them directly.
This is the architectural line that matters most for anything deployed to more than one instance: a client-server database has exactly one place where the data lives, no matter how many application processes are talking to it. A file database has as many copies as there are application instances, unless you go out of your way to make it otherwise.
When a file database is genuinely enough
A single-instance application, a local CLI tool, a desktop app, or a test suite that wants a real SQL engine without spinning up a container are all workloads where SQLite is not a compromise — it is the correct architecture. The backup is a file copy. There is no connection pool to tune and no separate service to keep alive.
Read-mostly data rebuilt entirely on each deploy is the other clean case: a documentation search index, a static content cache, anything where the data changes on a build rather than on a live request. If nothing writes to the file at runtime, most of the risk below simply does not apply.
Why file databases break on ephemeral container filesystems
Most modern hosting platforms run your application inside a container whose local disk is not guaranteed to survive a restart, a redeploy, or a scale event — the filesystem is treated as disposable, because the container itself is. A SQLite file written to that local disk disappears the moment the container is replaced, which is exactly what a redeploy does.
Scale to two instances and the problem compounds: each instance gets its own separate copy of the file, and they silently diverge with no error and no warning, because nothing coordinates between them. The symptom people actually report is close to what shows up in Uploaded Images Disappear After Deploy — the same ephemeral-filesystem failure mode, just applied to a database file instead of an image upload.
A persistent volume attached to the container closes the redeploy gap — the file survives a restart because it lives outside the container’s own disposable filesystem — but it does not close the multi-instance gap. Two containers both mounting the same volume and both opening the same SQLite file for writes is still an unsafe configuration; SQLite’s locking model assumes local disk semantics that most network-backed volumes do not reliably provide, and the documented failure mode is corruption, not a clean error. A persistent volume buys you single-instance durability, not concurrency.
When to move to managed Postgres or MySQL
The signal to move is any of: more than one application instance needs to write, you need backups you are not managing by hand with a cron job and a prayer, or you need to scale the application without also scaling a filesystem-coordination problem you never intended to own.
The move is usually smaller than people expect if the schema is already reasonably normalized, and it removes an entire category of bug — the one where the data was fine locally and silently wrong in production — permanently.
Start the migration by exporting the SQLite schema and data with the built-in .dump command, then adjust the small number of type differences by hand — SQLite’s dynamic typing is the main source of surprises, since a column that quietly accepted a string in SQLite will reject it outright once the equivalent Postgres column is declared as an integer or a timestamp. That audit, done once before the cutover, is cheaper than debugging the same type mismatch in production after the fact, and it is the same audit step covered in more depth for the SQLite-to-Postgres path specifically, not just the general shape of the move.
How this fits the rest of the stack
A managed database means persistent storage is the platform’s problem, not something you re-solve on every deploy or re-discover the hard way during an incident. If the current setup is a file quietly living in a container’s local disk, that is the exact gap a managed Postgres or MySQL instance closes — provisioned from the RunxBuild dashboard alongside the service that reads from it — and the RunxBuild hosting calculator shows what that combination actually costs.
Useful related references:
- SQLite vs PostgreSQL: Which One Your Project Actually Needs
- Free Sqlite Hosting: What Works Free and What Production Needs
- Uploaded Images Disappear After Deploy: The Ephemeral Filesystem Problem
- Storage on RunxBuild
FAQ
Is SQLite a flat file?
No. SQLite is a full relational database engine that happens to store everything in a single file. It supports real SQL, indexes, and ACID transactions, none of which a genuine flat file (a plain CSV or JSON blob) provides. The single-file storage is what causes the confusion, but the engine underneath is completely different.
Can I use a file database in production?
Yes, for single-instance workloads with a single writer — SQLite in particular is widely used in production for exactly that shape of application. It becomes the wrong choice once you need more than one application instance writing concurrently, or once you are deploying to a platform with an ephemeral filesystem without a persistent volume attached.
Why did my SQLite database disappear after I redeployed?
Most hosting platforms treat a container’s local filesystem as disposable and replace it on every deploy. If your SQLite file was written to that local disk rather than a persistent volume, the redeploy created a fresh container with no copy of the file, and the data is gone rather than merely hidden.
What’s the difference between a file database and a NoSQL database?
A file database (like SQLite) is typically a relational engine constrained to a single file with no separate server process. A NoSQL database is usually a distinct category defined by its data model — documents, key-value pairs, wide columns — and most NoSQL databases run as a client-server system over a network, the same architectural family as Postgres or MySQL, not the file-based one.
Is DuckDB a file database too?
Yes, in the same architectural sense as SQLite: no server process, one file, opened directly by your application. The difference is workload, not architecture — DuckDB is built for column-oriented analytical queries over larger datasets, while SQLite is built for general-purpose transactional row-based access.