PostgreSQL Until Proven Otherwise
Every project needs a database. Every project has opinions about which one. Here’s ours.
The default: PostgreSQL
When a client asks “what database should we use?”, our answer is almost always PostgreSQL.
Not because it’s trendy. Because it’s capable:
- Relational data — Obviously
- JSON documents —
jsonbis genuinely good - Full-text search — Often eliminates the need for Elasticsearch
- Geospatial — PostGIS handles most location use cases
- Time series — TimescaleDB extension when needed
One database. Multiple paradigms. Less operational complexity.
-- Postgres handles this without breaking a sweat
SELECT
users.name,
users.preferences->>'theme' as theme,
ST_Distance(users.location, point) as distance_km
FROM users
WHERE
users.bio @@ to_tsquery('engineer & paris')
AND users.preferences @> '{"notifications": true}'
ORDER BY distance_km
LIMIT 10;
When we reach for alternatives
Postgres isn’t always the answer. Here’s when we deviate:
Redis
For caching, sessions, rate limiting, and queues. Not as a primary database—as a supporting actor.
// Session store
await redis.setex(`session:${id}`, 3600, JSON.stringify(session));
// Rate limiting
const count = await redis.incr(`ratelimit:${ip}`);
await redis.expire(`ratelimit:${ip}`, 60);
SQLite
For embedded scenarios, edge computing, and local-first apps. Surprisingly capable for read-heavy workloads.
MongoDB
When the data is genuinely document-shaped and schema evolution is frequent. This is rarer than the hype suggests.
DynamoDB / Firestore
When the client is already deep in AWS/GCP and needs serverless scaling. Convenience over flexibility.
The anti-pattern
What we avoid: choosing databases based on scale you don’t have.
“But what if we get millions of users?” Then you’ll have money to solve that problem. Today, you have a product to ship.
The boring choice is usually the right choice. Postgres has been boring for 30 years. That’s a feature, not a bug.