An architecture plan, drawn up before there was a single user, carried this list: PostgreSQL for durable data, Elasticsearch for search, Redis for cache, MongoDB for flexible documents, RabbitMQ for queueing. Five separate data systems — each with its own backups, monitoring, version upgrades, and distinct failure mode.

Most of that list, for a long time, a single PostgreSQL carries on its own. The question isn’t “can PostgreSQL do this”; it’s “did you really buy the operational burden of these five systems”.

PostgreSQL’s little-known breadth

Treating PostgreSQL as just a table-row store uses a small fraction of what it can do. Most of the needs that prompt a separate system are already inside it:

  • Full-text search. A real search built on tsvector, tsquery, and a GIN index. It covers most apps’ “search products” and “search posts” needs, including stemming, weighting, and ranking.
  • Document storage. A jsonb column, paired with a GIN index, is a queryable document store. You can keep the fields that want schema flexibility right inside the relational table.
  • Queues. SELECT ... FOR UPDATE SKIP LOCKED and LISTEN/NOTIFY run a moderate-volume job queue without a separate broker. Laravel’s database queue driver uses the SKIP LOCKED half of it — its workers poll the jobs table at intervals rather than waiting on a LISTEN/NOTIFY signal.
  • Analytical queries. Window functions, CTEs, materialized views — serious reporting without reaching for a separate analytical database.
  • Geospatial data. Location queries via the PostGIS extension.

These features aren’t “present but unused”; they’re mature capabilities that run reliably in production.

The quiet payoff of a single system

Every new data system isn’t just a box; it’s a maintenance commitment. What you gain by staying on one system:

  • One backup line. One backup/restore procedure, one recovery drill.
  • One monitoring target. One set of metrics to learn, one alerting setup to build.
  • Cross-consistency. This is the most important one. If your search index lives in the same database as your data, there can be no drift between them — both update in the same transaction. A separate Elasticsearch will eventually fall out of sync with the data, and fixing that becomes its own line item.
  • One mental model. The team learns the quirks of one system, not five.

This is the data-layer version of the innovation-token logic from the boring architecture piece: every new system is a token, and tokens are limited.

Where the limit begins

PostgreSQL isn’t enough for everything — it has honest limits, and ignoring them is also a mistake:

  • Search. When typo tolerance, advanced relevance tuning, faceted search, and multilingual analysis are needed at serious scale, a dedicated search engine genuinely pays off.
  • Queues. When you need very high throughput, complex routing, or multi-consumer fan-out, a real message broker is the right tool. A PostgreSQL queue is comfortable at moderate volume, not at the extremes.
  • Write throughput. Sustained writes beyond a single primary’s fsync capacity — this is the hardest breaking point in data-intensive systems, and a real limit.

When you hit one of these limits, bringing in an extra system is the right call. Bringing it in before you hit it is just a guess.

The decision: PostgreSQL first, then measure

The rule is plain: in a new project, make PostgreSQL do everything PostgreSQL can do. Let it be the first stop for search, queue, and cache-like needs. A separate system should arrive only when a measured limit is crossed — not from a hunch, a blog post, or résumé anxiety.

Most teams use maybe 20% of PostgreSQL, then say “it’s not enough”. What’s not enough is usually not PostgreSQL, but the effort to get to know it.


PostgreSQL isn’t enough for everything — but it’s enough for far more than you think. Before you bring in a second data system, ask whether you’ve truly reached the end of the first.

PostgreSQL first; let the rest follow from measurement.