SQLite vs PostgreSQL: When to Switch (and When to Stay)
Published April 23, 2026 ยท 10 min read
SQLite powers more applications than any other database on earth. It ships in every iPhone, Android device, and most web browsers. PostgreSQL powers the backends of the world's most demanding SaaS platforms. Choosing between them โ or knowing when to migrate from one to the other โ is a decision every developer faces. This guide gives you a clear framework for when SQLite is enough, when PostgreSQL becomes necessary, and how to migrate without losing data or sleep.
What SQLite does better than PostgreSQL
SQLite is not a toy database. It is a production-grade, battle-tested embedded engine with distinct advantages:
- Zero configuration: No server to install, no port to configure, no users to create. The database is a single file.
- Zero latency: Because it runs in-process, queries execute with no network round-trip. For read-heavy workloads, this is unbeatable.
- Zero dependencies: SQLite is a single C library. It has no runtime requirements beyond libc.
- Perfect for testing: Spinning up a test database is as simple as opening a temporary file. Tear-down is deleting the file.
- Portable: A SQLite database file works identically on macOS, Linux, Windows, iOS, and Android.
- ACID compliant: SQLite writes are fully atomic, consistent, isolated, and durable. It passes the same durability tests as PostgreSQL.
If your application is a single-node service, a mobile app, a desktop tool, or a small web app with modest concurrency, SQLite is often the right choice. Don't let database fashion pressure you into running PostgreSQL when a file would suffice.
What PostgreSQL does better than SQLite
PostgreSQL is a full-featured client-server relational database with capabilities SQLite simply does not have:
- Concurrent writes: SQLite handles concurrency with file-level locking. Write throughput is limited to one writer at a time. PostgreSQL uses MVCC and allows hundreds of concurrent writers without blocking.
- User management and permissions: PostgreSQL has granular role-based access control. SQLite has no user system โ anyone with file access has full database access.
- Advanced data types: PostgreSQL supports arrays, JSONB, geometric types, ranges, UUIDs, and custom types. SQLite has five storage classes.
- Stored procedures and triggers: PostgreSQL PL/pgSQL is a full programming language. SQLite triggers are basic and procedures are nonexistent.
- Partial indexes and expression indexes: PostgreSQL can index subsets of data and computed expressions. SQLite indexes are simpler.
- Replication and high availability: PostgreSQL supports streaming replication, logical replication, and failover. SQLite has no built-in replication (though third-party tools exist).
- Parallel query execution: PostgreSQL can use multiple CPU cores for a single query. SQLite is single-threaded per connection.
- Full-text search: PostgreSQL has tsvector and tsquery. SQLite has FTS5, but it is less powerful and less commonly used.
The switching framework: 5 questions
Use these five questions to decide whether you need PostgreSQL or if SQLite is still sufficient:
1. Do you need more than one writer at a time?
SQLite's write concurrency model is simple: one writer, many readers. If your application has multiple processes or threads writing simultaneously, SQLite will serialize them. For low-volume writes, this is fine. For high-volume writes, it becomes a bottleneck.
Rule: If your application has >10 writes per second sustained, or unpredictable write bursts, consider PostgreSQL.
2. Do you need user-level access control?
SQLite has no authentication. File-system permissions are the only security boundary. If your database contains sensitive data and multiple applications or users need different access levels, PostgreSQL's role system is essential.
Rule: If more than one application or user class touches the database, use PostgreSQL.
3. Is your data larger than available RAM?
SQLite performs well when the working set fits in memory. For databases larger than RAM, PostgreSQL's query planner, parallel execution, and sophisticated caching generally outperform SQLite.
Rule: If your database exceeds 50% of available RAM and query performance matters, benchmark PostgreSQL.
4. Do you need advanced querying?
Window functions, common table expressions (CTEs), LATERAL joins, and recursive queries are all fully supported in PostgreSQL. SQLite supports window functions and CTEs, but with limitations. Complex analytical queries are PostgreSQL's strength.
Rule: If you write queries with multiple CTEs, window functions, or recursive logic, use PostgreSQL.
5. Do you need high availability?
SQLite is a single file. If the disk fails, the database is gone unless you have backups. PostgreSQL supports streaming replication, point-in-time recovery, and automatic failover.
Rule: If downtime costs money or reputation, use PostgreSQL with replication.
When to stay on SQLite
Many teams prematurely migrate to PostgreSQL. Here are situations where SQLite is not just acceptable โ it is superior:
- Embedded systems and IoT: A 500KB library beats a 100MB Docker container.
- Mobile applications: Core Data on iOS and Room on Android are both SQLite-based.
- Desktop applications: Firefox, Chrome, and VS Code all use SQLite for local storage.
- Small web apps: If your app serves <1,000 requests per minute and has <10 concurrent writers, SQLite on a fast SSD is often faster than PostgreSQL over a network socket.
- Data analysis pipelines: DuckDB has largely replaced SQLite for analytics, but SQLite remains excellent for ETL staging and small-scale analysis.
- Testing and development: Spin-up time for SQLite is milliseconds. For integration tests, this matters.
How to migrate from SQLite to PostgreSQL
If you've answered the five questions and decided to switch, here is a safe migration path:
Step 1: Export SQLite schema
sqlite3 mydb.db ".schema" > sqlite_schema.sql
Step 2: Convert the schema
SQLite and PostgreSQL are closer than MySQL and PostgreSQL, but there are still differences:
| SQLite | PostgreSQL | Notes |
|---|---|---|
INTEGER PRIMARY KEY |
SERIAL or GENERATED ALWAYS AS IDENTITY |
SQLite auto-increments on INTEGER PRIMARY KEY |
TEXT |
TEXT |
Direct equivalent |
REAL |
REAL |
Direct equivalent |
BLOB |
BYTEA |
Binary data storage |
BOOLEAN |
BOOLEAN |
SQLite stores 0/1; PostgreSQL stores true/false |
DATETIME |
TIMESTAMPTZ |
Always use TIMESTAMPTZ in PostgreSQL |
JSON |
JSONB |
JSONB is indexed and queryable |
Step 3: Compare schemas before migrating data
Paste your SQLite schema and converted PostgreSQL schema into SchemaLens to catch mapping errors before you move a single row. SchemaLens will flag type mismatches, missing constraints, and index differences.
Step 4: Export and import data
# Export SQLite to CSV
sqlite3 -header -csv mydb.db "SELECT * FROM users" > users.csv
# Import into PostgreSQL
psql -d mypostgres -c "COPY users FROM '/path/to/users.csv' WITH (FORMAT csv, HEADER true);"
For larger datasets, use pgloader โ a dedicated SQLite-to-PostgreSQL migration tool:
pgloader sqlite:///path/to/mydb.db postgresql:///mypostgres
Step 5: Update application connection strings
Replace SQLite connection logic with PostgreSQL connection pools. Most ORMs (Prisma, Sequelize, SQLAlchemy, Django ORM) make this trivial โ just change the connection string dialect.
Step 6: Verify
Run your full test suite against PostgreSQL. Check row counts, constraint behavior, and query results. Performance will differ โ some queries will be faster, others slower. Profile before optimizing.
Common migration gotchas
- Strict typing: SQLite is dynamically typed. You can insert a string into an INTEGER column and SQLite will accept it. PostgreSQL will reject it. Clean your data before migration.
- Foreign key enforcement: SQLite disables foreign keys by default. Many SQLite schemas have broken foreign keys that PostgreSQL will reject. Run
PRAGMA foreign_key_check;before exporting. - Auto-increment behavior: SQLite's
INTEGER PRIMARY KEYauto-increments. PostgreSQL requiresSERIALorIDENTITY. Map carefully or sequence values will conflict. - Date functions: SQLite's date functions (
date(),datetime(),strftime()) are different from PostgreSQL's. Update queries that manipulate dates. - LIKE case sensitivity: SQLite
LIKEis case-insensitive by default. PostgreSQLLIKEis case-sensitive. UseILIKEin PostgreSQL for case-insensitive matching.
The bottom line
SQLite and PostgreSQL are not competitors. They are tools for different jobs. SQLite is the right default for single-node, low-concurrency applications. PostgreSQL is the right choice for multi-user, high-concurrency, or complex-query workloads.
The mistake is not choosing one or the other. The mistake is refusing to switch when your requirements change. A startup that begins with SQLite and migrates to PostgreSQL at product-market fit is making a smart engineering decision. A startup that runs PostgreSQL from day one for a prototype with ten users is wasting money and complexity.
When you do switch, use SchemaLens to compare your SQLite and PostgreSQL schemas before moving data. Catching a type mismatch or missing constraint in the schema diff stage is infinitely cheaper than debugging data corruption in production.
Compare SQLite and PostgreSQL schemas โ
Related reading: