Concept · Requirements & scale

When not to add infrastructure

The cheapest, most reliable component is the one you never run.

2 minsimplicityYAGNI

Every component you add — a cache, a queue, a search cluster, another service — brings an operating cost and new failure modes: it must be deployed, monitored, upgraded, secured, backed up, understood at 3 a.m., and paid for. Good designs add components only when a requirement or a measured bottleneck demands one.

Questions to ask before adding something

  1. Which requirement fails without it? If you can't name one, don't add it.
  2. Can an existing component do it? PostgreSQL covers job queues (FOR UPDATE SKIP LOCKED), full-text search, JSON documents, geospatial queries and pub/sub (LISTEN/NOTIFY) for modest loads.
  3. What's the failure mode? A cache that's empty, a queue that's backed up, a search index that's stale — what does the user see?
  4. Who operates it? A managed service still needs someone who understands it.
  5. What does it cost at today's scale, and at 10×?

Common premature additions

AddedOften unnecessary because
Kafka for a few hundred events per secondA database-backed queue or a managed queue is far simpler
Microservices for a five-person teamA modular monolith deploys faster with fewer failure modes (monolith vs microservices)
A cache in front of a fast, lightly loaded databaseIt adds staleness and invalidation bugs for little gain
Sharding at a few hundred gigabytesOne well-indexed primary handles it
Elasticsearch for exact lookupsA database index does it

Design for change instead

You don't need the component now if you can add it later without a rewrite. Keep interfaces narrow (a Store interface the cache can wrap later), choose partition-friendly keys, and write events to an outbox table even before anything consumes them. Then add infrastructure when capacity estimation or monitoring says you need it.

Learn it in depth