Skip to main content

SQLite vs Postgres for a Side Project That Might Grow

Updated 5 min readMarkdown

Every side project starts the same way: one developer, one server, a database that just needs to work. The choice between SQLite and Postgres feels like it should matter a lot, and the internet will happily argue about it for hours. The honest answer is that it matters less than the arguments suggest — but the differences are real, and they show up at specific moments, not gradually.

Where SQLite wins

SQLite is a library, not a server. Your database is a single file on disk, and your application reads and writes it directly. There is nothing to install, nothing to run, nothing to configure, no connection string to a separate process, no user accounts, no port. You ship the file with the app, you back it up by copying it.

That simplicity is not a toy feature. For a side project, it removes an entire category of failure: the database server being down, the connection pool being misconfigured, the credentials being wrong on the new machine. It also makes local development identical to production, because there is no separate database to keep in sync. And SQLite is far more capable than its reputation — it handles complex queries, transactions, indexes, and full-text search, and it powers an enormous amount of software you use daily, from phones to browsers to airplanes.

For a project with one writer — one web server process, one background job, one user at a time doing writes — SQLite is usually the right call. Most side projects live in that shape for a long time. Some never leave it.

Where it breaks

SQLite's documented model is single-writer: one write transaction at a time, with other writers waiting. Reads can run alongside a write, but two writes serialize. For low-traffic apps this is invisible. Writes are fast — milliseconds — so the queue rarely forms.

It starts to matter when writes pile up: many users submitting forms at once, a background job bulk-importing rows while users are active, or several server processes all writing to the same file. The usual symptom is database is locked errors under load. You can tune the busy timeout to make writers wait longer instead of failing, but tuning doesn't change the shape — one writer at a time, in sequence.

The second break point is architecture. SQLite is a file, so it lives on one machine. The moment you want two app servers for redundancy, or a separate worker machine, a file on one disk stops fitting. You can work around it, but those workarounds are where the simplicity evaporates.

Where Postgres earns its keep

Postgres is a real server, with everything that implies: connections, users, permissions, configuration, backups to manage. That's overhead, and for a side project it's the main cost — not money, but attention. The payoff is concurrency and scale. Many writers at once, handled properly. Multiple app servers connecting to the same database. Replication, connection pooling, advanced indexing, JSON columns with real query support.

The migration path

This is the part the arguments usually skip: moving from SQLite to Postgres later is not a rewrite. Both speak SQL, and for the ordinary queries a side project uses, the SQL is mostly the same. The work is in the differences: SQLite is loose about types where Postgres is strict, and any SQLite-specific functions need replacing. An ORM smooths most of this; raw SQL needs a careful pass.

The migration itself is a known job: dump the data, translate the schema, load it into Postgres, point the app at the new connection. People do it all the time. It's a weekend's work for a small project, not a month. Which means the choice isn't permanent, and the fear of choosing wrong is overblown.

The decision rule

Pick SQLite if the project has one writer, runs on one machine, and you want to spend your time building features instead of operating a database. That's most side projects, and it's the right default.

Pick Postgres if you already know writes will be concurrent — multiple users writing at once, background jobs writing while users are active — or if the project is meant to run on more than one server from the start.

And if you're genuinely unsure, pick SQLite and keep your SQL portable: avoid SQLite-only functions, use an ORM or a thin data layer, and don't bake the file path into fifty places. The cost of migrating later is real but small; the cost of operating Postgres for a project that never needed it is paid every week, in attention, from day one.


P.S. Everything I write stays free — that part doesn't change. But if this one was worth something to you, you can buy me a coffee ☕ (one-time or monthly, both work). It covers the API credits and hosting behind these experiments — and honestly, it's also the nudge that gets the next one started on the evenings I'd otherwise skip it. — Salam

Buy me a coffee

No comments yet. Be the first to comment.

More from this blog