SEO keyphrase: Only Postgres for MVPs
TL;DR
- Most MVPs and small systems work very well with Only Postgres for MVPs, without Redis, Elasticsearch, or a dedicated vector database.
- Modern PostgreSQL already handles simple caching, text search, filters, reports, basic queues, and even vector search through extensions.
- Instead of guessing about bottlenecks too early, start simple, measure, and add new components only when the pain is real.
- The goal is not “Postgres forever,” but “Postgres as a safe default” plus an architecture that can evolve later, with specialized tools when they make sense.
1. Context: Why Are We Complicating Things So Early?

A classic scene.
You open the repository of an MVP that does not even have ten users yet and find:
- A microservices API—three or five services, obviously.
- Redis for caching.
- Elasticsearch for search.
- A vector database “because we are going to use AI at some point.”
- A queue—Kafka or RabbitMQ—“so we are ready to scale.”
And the business problem is still being defined.
This often turns into a kind of “LinkedIn résumé” architecture: a collection of sophisticated components, with little clarity about the actual need. The result is a team spending energy bringing up, configuring, monitoring, and debugging infrastructure while the product is still trying to discover whether anyone wants to use it.
Why does this happen so often?
- Technical FOMO: fear of “falling behind” by not using the latest popular stack.
- The wrong scale reference: copying Netflix’s or Meta’s architecture for a SaaS with 50 customers.
- Confusing “it may be useful someday” with “I need it today.”
The thesis of this article is simple:
For many MVPs, Only Postgres for MVPs is a safer, cheaper, and easier-to-operate starting point. And if it succeeds, you can still evolve later.
This is not a manifesto against Redis, Elastic, or vector databases. These tools are excellent—in the right context. The focus here is the timing of complexity: delaying the cost of operating a technology zoo until you actually need it.
If you would like to see the same discussion in presentation format, check out the Only Postgres for MVPs talk, which explores this reasoning in another context.
2. What a Well-Used “Only Postgres” Setup Already Solves

Many people still see PostgreSQL only as “a relational database that handles CRUD and joins.” But modern PostgreSQL provides much more than that and covers several needs that teams outsource to other tools far too early.
Important PostgreSQL capabilities today
Some commonly underused features include:
- Various index types
BTREE: the basic choice for equality and ordering.GIN: excellent for indexing arrays, JSONB, and full-text search.GiST: supports geometric data, proximity searches, and some full-text scenarios.-
BRIN: useful for very large tables, especially when data is naturally ordered. -
JSONB and semi-structured data
- Lets you store less structured parts of the domain without leaving Postgres.
-
Useful for metadata, per-customer settings, integration payloads, and more.
-
Native full-text search
- With
tsvector/tsquery, stemming, basic ranking, and stop words. -
You can build a reasonably capable search for titles, descriptions, and text content.
-
Extensions
pg_trgm: similarity search, useful for autocomplete and corrections.pgvector: vector columns for AI—we will discuss this later.-
Other extensions can solve specific niches, but for an MVP these two already cover a lot of ground.
-
Useful concurrency mechanisms
FOR UPDATE SKIP LOCKED, for example, allows you to implement concurrent queues in a task table, preventing two workers from processing the same record.
Together, these features already support use cases such as:
- Simple caching.
- Basic queues.
- Text search.
- More demanding reports and filters.
- Early generative AI use cases with RAG.
This does not mean PostgreSQL replaces caching systems, distributed queues, search engines, or vector databases in every context. It means that, during the MVP phase, it is often “good enough” to avoid introducing those other components too early.
Architectural benefits of starting with a single database
When you choose Only Postgres for MVPs, several benefits appear naturally:
- Fewer components → fewer failure points
- One fewer instance—or cluster—to deploy, monitor, and pay for.
-
Less latency between services; many operations become simple database calls.
-
Simpler operations and observability
- Centralized backups.
- Monitoring focused on a single stack—Postgres metrics plus application logs.
-
Tuning concentrated in one place.
-
A team focused on the product
- Less time configuring pipelines, operating queues, and deploying new services.
- More time validating business hypotheses, listening to users, and improving the flow.
This reasoning is explored in more detail in the Only Postgres for MVPs analysis, which examines why many MVPs do not need to start with Redis, Elasticsearch, or a dedicated vector database.
Example: a simple B2B SaaS
Imagine a B2B SaaS product for managing sales proposals:
- Basic entities:
- User, company, customer, proposal, proposal item, attachment.
- Features:
- CRUD for customers and proposals.
- Filters by status, date, amount, and owner.
- Monthly report of approved versus rejected proposals.
- Basic authentication—username/password, perhaps an email OTP.
What does this system need?
- Fast CRUD → BTREE indexes on primary keys and filter columns.
- Filters and reports → queries with aggregation (
SUM,COUNT,GROUP BY), perhaps views. - Simple search → full-text search on proposal titles and descriptions, or
pg_trgmfor searching customer names. - Sessions/authentication → a users table plus session or refresh tokens.
All of this fits comfortably into a single Postgres database with:
- A clear relational schema.
- A few indexes planned based on real queries.
- Some full-text or trigram search if needed.
None of these needs, by default, requires you to deploy Redis, Elasticsearch, or a vector database on day one.
3. Replacing the “Redis + Elastic + Vector Database” Trio with Postgres—for Now
Let us look at three classic cases where teams tend to introduce new technologies too early—and how Postgres can handle much of the workload before you need to add complexity.
The point is not to say that Postgres is better than these tools, but to show how far it can go during an MVP phase.
3.1. When You “Think” You Need Redis
Typical cases where someone shouts “Redis!” during MVP planning include:
- Read caching for frequently accessed endpoints, such as
/meor a product list. - Centralized user sessions.
- Rate limiting to prevent API abuse.
These use cases make sense in larger systems, but in an MVP the problem often is not there yet.
What you can do with Postgres alone
- “Implicit” caching through indexes and good queries
In many cases, the problem is not “I need caching,” but rather:
- There is no index on the filtered column.
- The query runs
SELECT *against a huge table. - Lists have no pagination.
The combination of:
- The right indexes—BTREE on filtered columns, GIN on JSONB when necessary.
- A focused query that selects only the required columns.
- Proper pagination.
already reduces response times considerably, to the point where an external cache is not a priority at the beginning.
- User sessions in Postgres
Instead of storing sessions in Redis, you can:
- Create a
sessionstable with: user_id.- A token or refresh token.
- Small pieces of data in
JSONB, such as the user agent and IP address. created_atandexpires_at.
Or, more simply, use JWTs with a short lifetime and store only refresh tokens in the database. For an MVP, the scale is usually low enough for this to be sufficient for quite a while.
- Rate limiting with lightweight tables
You can create an api_usage table with:
user_id.endpointor an operation key.window_start, such as the beginning of the current minute.count.
With a composite index on (user_id, endpoint, window_start), you can apply a limit per user and endpoint for each time window. This is not as efficient as Redis at extremely high scale, but it works well for MVPs and systems with low to moderate traffic.
Practical limits: when Redis starts to make sense
On the other hand, insisting on using Postgres for everything also has limits. Redis starts to make sense when:
- The Postgres instance is struggling with very frequent repeated reads.
- Network latency must be extremely low with a high request volume.
- Traffic spikes are difficult to absorb with Postgres alone, even after optimizing indexes and queries.
In these cases, Redis for hot caching or more aggressive rate limiting is a useful complement. The difference is starting simple and introducing Redis when the problem is clear, rather than doing so out of habit.
3.2. When You “Think” You Need Elasticsearch
Another common scene: an MVP with half a dozen screens already has an Elasticsearch cluster because “we will need powerful search.”
Typical arguments include:
- “We need Google-style autocomplete.”
- “Advanced filters everywhere.”
- “Sophisticated relevance-based search.”
Sometimes that makes sense, but for most MVPs, it is still too early.
What Postgres provides natively for search
- Full-text search (
tsvector/tsquery)
You can:
- Create a
search_vectorcolumn of typetsvector. - Populate it from the title, description, and content.
- Create a GIN index on
search_vector. - Run queries with
to_tsqueryorplainto_tsquery.
This lets you:
- Search for terms.
- Use stemming—finding “running” when searching for “run,” for example.
-
Rank results with
ts_rank. -
pg_trgmfor similarity search
With the pg_trgm extension, you can:
- Make
LIKEqueries more efficient. - Implement “similar to” or fuzzy search.
-
Build simple autocomplete by prefix or similarity.
-
Well-used GIN/GiST indexes
Combined with tsvector or pg_trgm, these indexes can significantly improve the response time of searches and filters without leaving Postgres or operating a separate cluster.
Example: searching products or blog posts
Imagine a product catalog with:
- Name.
- Description.
- Tags.
You can:
- Create a
search_vectorcolumn by concatenating the name, description, and tags and converting them totsvector. - Index it with GIN.
- Run queries that:
- Filter by category and price.
- Search for a text term in
search_vector. - Sort by basic relevance ranking or by date.
For an MVP, this handles most catalog or content search use cases well.
Practical limits: when Elasticsearch shines
Elasticsearch starts to justify its cost when:
- You have many documents and complex relevance-based queries.
- You need facets and more sophisticated aggregations at scale.
- You require a distributed cluster with high availability specifically for search.
- You use advanced ranking features, synonyms, boosting, ingest pipelines, and so on.
Until then, Only Postgres for MVPs with full-text search and pg_trgm covers a significant share of use cases without forcing you to operate another critical component.
3.3. When You “Think” You Need a Vector Database
In the post-ChatGPT world, the hype has shifted:
- “Our MVP needs generative AI.”
- “We are going to build RAG—Retrieval-Augmented Generation—from day one.”
- “I deployed a dedicated vector database, so now I am ready for the future.”
For many AI MVPs, this is more complexity than necessary.
What already exists in the Postgres ecosystem
Postgres now has extensions such as:
pgvector: adds a vector data type and indexes for similarity search—cosine distance, L2, and others.
In practice, you can:
- Have a
documentstable with: id,title, andcontentas regular columns.embeddingas a vector column provided bypgvector.- Insert the content and embedding generated by an external model.
- Run vector similarity queries to retrieve relevant documents.
With this, you can build a basic RAG system using only Postgres and pgvector, which is enough for many proofs of concept and pilots.
Why this is enough for many AI MVPs
Many AI MVPs:
- Have few documents—hundreds or a few thousand.
- Have a low query frequency—a demo, proof of concept, or paid pilot.
- Do not require ultra-low latency.
Under these conditions, Postgres with pgvector performs well:
- Fewer components to administer.
- Lower infrastructure costs.
- Easier for the team to maintain and debug.
Practical limits: when a dedicated vector database is justified
Dedicated vector databases start to make sense when:
- You have large datasets—on the order of millions of vectors.
- You need very low latency for frequent vector queries.
- You want advanced partitioning, index caching, and replication features specific to this type of data.
Reaching this point is usually a great sign: it means your AI product has moved beyond the MVP phase and reached a different level. But you do not need to start there.
4. How Far Does Postgres Go? Signs That Everything Is Still Fine

How do you know whether Only Postgres for MVPs is still a healthy choice for your context?
Checklist: “Everything is fine—keep using Only Postgres”
Some signs that things are under control:
- Average latency is acceptable under realistic load
- The most common requests respond within a time appropriate for your use case.
- The database is not an obvious bottleneck
- CPU is usable, I/O is within normal levels, and locks are under control.
- Your domain still fits into a clear schema
- It has not become a tangle of tables and JSONB that nobody understands.
- Your team understands most of what is running
- The main queries are readable.
- Indexes are not a black box that nobody knows how to justify.
Simple metrics to track
Without building a huge observability stack, you can already get useful signals by looking at:
- Average execution time of the most common queries
- Track the 10–20 most frequently executed queries: are they stable or getting worse?
- Active connections versus the limit
- Check whether you are approaching
max_connectionsor whether the connection pool is poorly configured. - Growth of the main tables
- Are tables growing too quickly? Is it time to consider partitioning or cold storage?
Tools such as pg_stat_statements and the slow query log already provide a lot of value without requiring a complex ecosystem around them.
Pitfall: premature optimization
Common mistakes in this discussion include:
- Adding caching everywhere before measuring.
- Introducing a queue, Redis, and Elastic “because it is more professional.”
- Estimating high-scale problems without having traffic that justifies the concern.
There is no bonus for the number of technologies in an MVP. In general, this increases technical debt and failure points without providing a real benefit during the early phase.
5. When “Only Postgres” Actually Starts to Hurt
It is also important to acknowledge the other side: Postgres cannot handle everything forever. How can you tell that you are reaching the healthy limit of an Only Postgres for MVPs model?
Clear signs that it is time to add other components
- Postgres became a bottleneck even after basic optimization
You have already:
- Adjusted indexes based on real queries.
- Reviewed the most frequently used queries.
- Fixed N+1 queries and unnecessary access.
- Adjusted basic memory and connection settings.
Even so:
- Latency remains high under real usage.
- CPU and I/O are constantly near their limits.
-
Lock contention is frequent.
-
Very different access patterns are competing for the same database
A common example is:
- Transactional workload—application CRUD—coexisting with:
- Heavy reports.
- Intensive batch processes.
- BI analytics querying the production database directly.
This often calls for:
- Dedicated read replicas for reports.
- A separate data warehouse.
-
Queues or events to feed other databases.
-
Latency or availability requirements that tuning alone cannot meet
If you need:
- A very strict millisecond-level SLA.
- Extremely high write concurrency.
- Complex geographic distribution.
…it may be time to:
- Add caching with Redis.
- Use queueing mechanisms.
- Split responsibilities across more than one specialized system.
Examples of scenarios where moving beyond Only Postgres makes sense
Some examples include:
- Adding Redis for distributed caching when:
- You have extremely demanding read endpoints accessed at high frequency.
-
The response can be reused for many users.
-
Using a queue—Kafka or RabbitMQ—when:
- Asynchronous processes are heavy and affect the user experience.
-
You need to scale workers independently and support structured reprocessing.
-
Introducing Elasticsearch when:
- You have many documents and need advanced search, heavy facets, and finely adjustable relevance.
- Search is important enough to justify a dedicated cluster.
In these scenarios, Postgres remains part of the solution, while specialized tools address specific demands that the database alone cannot handle comfortably.
6. A Practical Strategy: How to Start with Only Postgres Without Getting Trapped

A legitimate concern is: “If I start with Only Postgres for MVPs, will I lock myself into a path with no way back?”
In practice, this depends much more on how you organize your code than on the technology itself.
Modeling with future evolution in mind
Some practical ideas:
- Separate application layers
- Use something like ports and adapters, hexagonal architecture, clean architecture, or at least an
inframodule that isolates data access. -
Avoid scattering raw SQL throughout the codebase.
-
Avoid depending on highly specific details too early
- If you know you may migrate from Postgres full-text search to Elastic in the future, hide that behind a
searchinterface. - The same applies to caching: implement a cache interface that talks to Postgres today and can talk to Redis tomorrow.
This lets you start with Only Postgres for MVPs without blocking future evolution.
Example: designing cache and search interfaces
- Cache interface
You might have something like:
CacheService.get(key)CacheService.set(key, value, ttl)
At the beginning:
- Implement
CacheServiceusing acache_entriestable in Postgres.
In the future, if necessary:
- Implement a new version of
CacheServiceusing Redis. -
The rest of the system does not need to know that the backend changed.
-
Search service
Create something like:
SearchService.searchProducts(query, filters)SearchService.searchArticles(query)
At first:
- Implement it using full-text search—
tsvector—andpg_trgmin Postgres.
If you need to scale later:
- Implement another
SearchServicethat calls Elasticsearch. - Migrate the data gradually, switching the implementation with a feature flag if necessary.
Good practices for using Postgres in this context
A few precautions help sustain this strategy:
- Monitor from the beginning
- Enable the slow query log.
-
Use
pg_stat_statementsto understand what is actually being executed. -
Create indexes incrementally
- Avoid creating indexes on everything “just in case.”
-
Add indexes as real queries appear and are measured.
-
Be careful with obscure extensions
pg_trgm,pgvector, and the full-text search engine are relatively well established.- Very unusual extensions can make version upgrades or migrations more difficult.
How to communicate this strategy to the team and stakeholders
Finally, there is the alignment work:
- For the technical team:
- “We will start simple with Only Postgres for MVPs, but the architecture is designed to support adding or replacing services later.”
-
Show how interfaces for caching, search, and queues allow infrastructure details to change without rewriting the domain.
-
For stakeholders—product, business, and leadership:
- Explain the cost of carrying technologies that may never actually be used.
- Emphasize that adding Redis, Elastic, or a vector database is not forbidden—it is simply a decision we want to make based on data, when the pain appears.
7. Conclusion: The Power of Delaying Complexity
The central point of this article is not that “Postgres is the answer to everything.” It is something more pragmatic:
Postgres is an excellent “safe default” for starting most MVPs.
It offers:
- Modern features—JSONB, full-text search, and extensions such as
pg_trgmandpgvector. - Relatively simple operations.
- A known path for evolution—replicas, partitioning, and offloading to other tools.
The suggested strategy is:
- Use Only Postgres for MVPs as the default.
- Measure performance and track a few simple metrics.
- Optimize the basics—indexes, queries, and configuration.
- Then add Redis, Elasticsearch, a dedicated vector database, or queues when the problems are clear and measurable.
PostgreSQL can solve many common needs—such as simple caching, basic queues, text search, and even early AI use cases with extensions—but these solutions do not replace specialized tools in every scenario. At some point, it makes sense to bring in dedicated systems to scale specific types of workloads more effectively.
Healthy architecture is not the architecture with the most logos on the diagram. It is the one that grows with the product—neither before nor after it needs to.
If you have experienced technology overload in an MVP, consider sharing your experience with other software developers. These stories help prevent the next project from starting with more infrastructure than users.
- Join the SCCB community — https://instagram.com/software_craftsmanship
- See upcoming events — https://instagram.com/software_craftsmanship
Next Steps
If you want to put this approach into practice on your next project:
- Make Postgres the explicit default
-
Document it in the project README: “We will start with Only Postgres; Redis, Elastic, and other tools will be added only if metrics X/Y/Z show a problem.”
-
Map infrastructure interfaces early
- Identify where abstractions make sense: caching, search, and queues/events.
-
The goal is not to create layers for their own sake, but to avoid tight coupling to a specific solution.
-
Configure the minimum observability required
- Enable the slow query log and
pg_stat_statements. -
Create a simple dashboard to track average query time and connections.
-
Review your current architecture
-
If your low-traffic MVP already has Redis, Elastic, or a vector database, ask:
- “Which parts are actually being used?”
- “What could be handled by Postgres again without significant pain?”
-
Share lessons with the team
- Use this discussion to align expectations: neither 8—an indexless chaotic monolith—nor 80—a distributed cluster with no users.


