sethserver.com Subscribe
A cartoon robot with a coral-pink colored cubic body sits at a blue desk, holding a pencil while working on a large yellow grid/spreadsheet. The background is mint green with floating database icons and checkmarks scattered around the scene.

SQLite Is Probably Enough

By Seth Black • Updated: January 26, 2026

Programming · 3 min read

Like this kind of writing? Get one email a week with notes on startups, AI, and the occasional strong opinion about Python: subscribe to the newsletter.

There's a popular startup reflex that goes like this: "We should use Postgres because we're going to scale." That's like buying a tour bus for your daily commute because someday you might make money from carpooling.

SQLite is reliable and usually the right answer. It's a single-file database with a serious track record. It also deletes an entire category of problems: provisioning, credentials, network hiccups, and connection pools. And yes, I know there's a loud "Postgres for everything" crowd. I'm pretty sure y'all are the same people who insisted I needed microservices for a todo app.

When SQLite is genuinely fine

SQLite shines when your app is mostly reading, or when it runs in one place:

If you're building something like "upload PDFs and search them," SQLite plus a decent indexing strategy will handle more than you think. It can pretty easily power apps with millions of rows.

The real limit: write contention (a.k.a. the one-writer rule)

SQLite can handle lots of reads and some writes, but it has a key constraint: only one writer at a time.

That means high write concurrency (many users constantly writing) can cause:

Things that help (but aren't silver bullets):

Two lines that make SQLite significantly better at handling concurrent access:

PRAGMA journal_mode = WAL;
PRAGMA synchronous = NORMAL;

Not "The Solution" but "A Solution"

If your product is write-heavy by nature (chat, high-frequency events, multi-tenant OLTP under load), SQLite isn't the write...wright...rite...correct choice. When you're building from the ground-up and don't want to worry about RDBMs setup on day one do this:

  1. Use an ORM or query layer that supports both (SQLAlchemy, Django ORM, etc.).
  2. Keep SQL portable: avoid vendor-specific features until you need them. (You probably don't. Yet.)
  3. Centralize database access behind a repository/service layer.
    Future-you should not have to grep 400 files because Past-you got excited and inlined SQL in a view handler. Past-you is unreliable.
  4. Use migrations from day one (Alembic, Django migrations, Flyway).

Here's the basic SQLAlchemy setup. This is the magic incantation that gives you a clean seam for swapping databases later:

# db.py
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker

engine = create_engine("sqlite:///app.db", future=True)
SessionLocal = sessionmaker(bind=engine, autoflush=False, autocommit=False)

Later, swapping to Postgres becomes a config change, not a rewrite.

Connection sanity (because people love making this weird)

SQLite also pairs nicely with my "stop making 10,000 connections" philosophy. You don't need a pool the size of a small nation. You need clean boundaries and predictable access patterns. (I've written about connection pooling insanity before - same principles apply.) If you want the official knobs and dials, the SQLAlchemy engine docs are here: https://docs.sqlalchemy.org/en/20/core/engines.html

SQLite is probably enough. And if it isn't, you'll know because production will tell you. Not because you read it in a blog post.

-Sethers

Share this post
Newsletter

One email, once a week.

Notes on databases, systems, and the occasional strong opinion about Python. No spam, unsubscribe anytime.

Seth Black
Written by

Seth Black

Engineer and founder based in Texas. Writes about databases, AI, and running things in production. Embeds in small teams as lead engineer.

More from Programming

View all →
Programming

What's the Differences Between Relational, NoSQL, Vectors, and Caches

Apr 14, 2026
Programming

Git and Source Control in AI Land

Apr 14, 2026
Programming

Domains, DNS, and why it feels fragile

Apr 14, 2026