Engineering
When PostgreSQL Is Enough — Stop Adding Infrastructure Your SaaS Doesn't Need
Most SaaS backends running on PostgreSQL don't need Redis, Kafka, Elasticsearch, or a separate queue. Here's when the database you already have is the right tool — and when it isn't.
The default SaaS architecture in 2026 is a stack of services: PostgreSQL for persistence, Redis for caching, a queue (RabbitMQ/SQS) for background jobs, Elasticsearch for search, Kafka for events, and a separate object store for files. It's what every tutorial shows. It's what every "scalable architecture" diagram includes. It's what most teams deploy on day one — before they have a single user.
Here's the uncomfortable truth: PostgreSQL can replace most of that stack for the first several years of your SaaS product's life. Not as a compromise. Not as "good enough for now." But as a deliberate architectural choice that reduces operational surface area, speeds up development, and eliminates entire categories of production incidents.
This post is about knowing when the stack you already have is sufficient — and when you genuinely need to add something new.
The Infrastructure Tax
Every service you add to your stack carries a tax:
Each of these solves a real problem. The question is whether you have that problem yet. Most teams don't — they have 1,000 daily active users, 10 GB of data, and a PostgreSQL instance that's running at 3% CPU. The infrastructure tax is being paid for problems that don't exist.
What PostgreSQL Can Actually Do
PostgreSQL in 2026 is not the PostgreSQL of 2016. Extensions and built-in features have absorbed the use cases that used to require separate services:
| Use Case | Service You Think You Need | PostgreSQL Alternative |
|---|---|---|
| Caching | Redis | UNLOGGED tables, materialized views, pg_prewarm. For most read-heavy workloads with moderate QPS, PostgreSQL's shared buffers + unlogged tables beat Redis on simplicity with acceptable latency. |
| Background jobs | RabbitMQ, SQS, Redis (Sidekiq) | SKIP LOCKED queries, pg_cron, now pg_durable for durable execution. A jobs table with SKIP LOCKED handles millions of jobs per day without a separate queue. |
| Full-text search | Elasticsearch | tsvector, GIN indexes, websearch_to_tsquery, pg_trgm for fuzzy search. PostgreSQL full-text search handles most SaaS search needs — product catalogs, user search, document search — without an Elasticsearch cluster. |
| Event stream | Kafka | LISTEN/NOTIFY + triggers, logical replication slots. Not Kafka-scale throughput, but enough for the event-driven patterns most SaaS products need. |
| Analytics | ClickHouse, BigQuery | BRIN indexes, table partitioning, parallel query, materialized views. For datasets under 100 GB, PostgreSQL analytics is faster than the network round-trip to a separate analytics DB. |
| File storage | S3-compatible store | BYTEA or Large Objects for small files. Not a full replacement — use S3 for user uploads — but many teams run an S3 service for internal files that could live in the database. |
This isn't theoretical. Companies running $10M-$50M ARR SaaS products use PostgreSQL for all of these. The database you already have is more capable than the infrastructure you're tempted to add.
When You Actually Need the Extra Services
This isn't an absolutist argument. There are real thresholds where PostgreSQL stops being the right tool:
When You Need Redis
- Session stores with sub-millisecond latency and 10,000+ concurrent reads. PostgreSQL shared buffers add 1-2 ms; Redis is 0.1-0.3 ms. If that gap matters — and it does for high-frequency session access — add Redis.
- Rate limiting at high throughput. Redis INCR + EXPIRE is purpose-built for this. PostgreSQL UPDATE with RETURNING works but adds latency.
- Pub/sub at 100,000+ messages/second. LISTEN/NOTIFY tops out around 10,000-20,000 messages/second in practice. Beyond that, Redis Pub/Sub or a proper queue is necessary.
When You Need a Queue
- Workers in different languages. If your background jobs run Python but your API is Node.js, a queue protocol (AMQP, SQS) is the lingua franca.
- Guaranteed delivery with complex routing. Topic exchanges, dead-letter queues, message TTL — these are queue-native features.
- Throughput above 5,000 jobs/second sustained. SKIP LOCKED polling hits connection limits and latency overhead at very high throughput.
When You Need Elasticsearch
- Faceted search with aggregations across millions of documents. PostgreSQL tsvector handles text matching; Elasticsearch handles "show me all products in category X, price $50-$100, sorted by rating, with facet counts for brand and color."
- Search across 50+ million documents. GIN indexes on tsvector work at this scale but query planning gets unpredictable.
- Geospatial search at scale. PostGIS is excellent for geospatial. For complex polygon intersections across millions of rows with sub-second response, Elasticsearch's geospatial optimizations pull ahead.
When You Need Kafka
- Multi-service event-driven architecture with 5+ consumer groups. PostgreSQL logical replication is single-consumer. Kafka's consumer group model handles multi-service architectures natively.
- Event replay and time-travel. Kafka's log-based storage lets you replay events from any offset. PostgreSQL doesn't offer this without application-level event sourcing.
- Throughput above 50,000 messages/second. Not a PostgreSQL workload at this scale.
The Indian SaaS Context
Indian SaaS companies operate in a specific cost environment. A managed Redis instance on AWS Mumbai costs roughly ₹3,500/month ($42). A managed Elasticsearch domain starts at ₹12,000/month ($144). A managed Kafka cluster: ₹40,000+/month ($480+). For a bootstrapped startup or an SMB SaaS product, these are meaningful line items — especially when multiplied across dev, staging, and production environments.
More importantly, each service is an operational liability. Every additional service is a thing that can:
- Run out of memory during a traffic spike
- Drift from the database state
- Require version upgrades that break your client library
- Generate alerts that wake someone up at 3 AM
- Need backup and restore procedures that differ from PostgreSQL's
For a team of 2-5 engineers — the typical Indian SaaS startup — reducing the infrastructure footprint isn't about cost savings. It's about operational survival. Every service you don't run is a service that can't break.
A Decision Framework
When someone proposes adding a new service to the stack, ask three questions:
What specific bottleneck are we solving? The answer must include a metric: current throughput, current latency, expected growth. "It's the standard architecture" is not a bottleneck.
Have we exhausted PostgreSQL-native solutions? Have you tried UNLOGGED tables before proposing Redis? SKIP LOCKED before proposing SQS? tsvector before proposing Elasticsearch? If the answer is no, the proposal is premature.
What's the operational cost? Not just the monthly bill. The monitoring, backup, upgrade, incident response, and onboarding cost. If you can't quantify this, you can't evaluate the trade-off.
Bottom Line
PostgreSQL is the most capable general-purpose database in existence. In 2026, with extensions like pgvector, pg_cron, pg_durable, PostGIS, and pg_partman, it absorbs use cases that used to require 3-5 separate services. Most SaaS products will never outgrow it.
The discipline isn't knowing when to add infrastructure. It's knowing when not to. Most teams add too early, pay the operational tax for years, and only realize the mistake when they're debugging a production incident across five services — for a product with 500 daily active users.
Start with PostgreSQL. Add services when you've measured a bottleneck, exhausted database-native solutions, and accepted the operational cost. That's not "good enough for now." That's good engineering.
Tags
- postgresql
- saas
- architecture
- infrastructure
- indian-startups
More on engineering
- Microsoft Open-Sources pg_durable — Durable Execution Moves Inside PostgreSQLMicrosoft released pg_durable on June 5, 2026, bringing durable execution directly into PostgreSQL as an extension. Define workflows in SQL, let Postgres checkpoint each step, survive crashes without external orchestrators. Here's what it does, who it's for, and why it matters.
- Durable Execution Explained — The Pattern That Makes Your SaaS Actually WorkDurable execution is the difference between a SaaS that silently drops data during a restart and one that picks up exactly where it left off. Here's what it is, why most implementations get it wrong, and how to build it without overengineering.
- Connection Pooling Is Not Optional — PostgreSQL at Scale for Multi-Tenant SaaSEvery Rails/Django/Node.js tutorial ships with a database.yml that opens 5 connections. Multi-tenant SaaS at 200 tenants means 1,000 connections. PostgreSQL falls over around 300. Here's how connection pooling — specifically pgbouncer — prevents the crash you're heading toward.