We've all been there. You're in a technical planning meeting, and someone inevitably asks: "Should we use MongoDB for this?" The question hangs in the air like a challenge to your engineering credibility. Say yes, and you're modern, scalable, "cloud-native". Say no, and you risk being labeled as that developer who still thinks it's 2005.
But here's the uncomfortable truth: most applications reaching for NoSQL databases are solving problems they don't actually have yet, while creating new ones they definitely don't need.
Let me be clear from the start, this isn't an indictment of NoSQL technologies themselves. These databases exist because they solve real problems for real companies. The issue isn't with the tools; it's with how they're often positioned as the goto choice for developers who often haven't yet encountered the specific problems they're designed to solve.
The seductive promise of "schema-free"
The NoSQL pitch is compelling, almost irresistible. Why lock yourself into rigid schemas when you could let your data model evolve on the fly? Why think about JOINs at all when you can just embed everything into a single document? It feels like freedom. A clean break from the constraints of relational thinking.
But “schema-free” is a misnomer. Your application still has a schema. It is just implicit, undocumented, and scattered throughout your codebase. Every time you write something like user.preferences.notifications.email, you are baking in assumptions about structure and shape. The difference is that PostgreSQL will tell you immediately when those assumptions are wrong. MongoDB tends to wait until 3 a.m. on a Sunday to surprise you, usually via a production error.
Now ask yourself this. How often have you truly needed to store fundamentally different document shapes in the same collection? Not small variations on a theme, like optional fields or feature flags, but genuinely different structures living side by side. If you are honest, the answer is probably close to zero. Most of the time we are storing users, orders, products, and other well-defined entities. These are interfaces with predictable, stable structures, whether we choose to acknowledge that or not.
Once you accept that reality, the next question becomes harder to ignore. If your data is structured anyway, what are you actually gaining in return for giving up the guarantees of a relational system?
The operational complexity tax
This is where the real cost starts to show. SQL databases come with an ecosystem that has been built up over decades. Every operations engineer knows how to back them up, monitor them, and tune them. Performance tooling is mature. Recovery procedures are well understood. The hiring pool is deep.
NoSQL databases, for all their promises, often feel more like engineering archaeology. Each one comes with its own query language, its own performance quirks, and its own failure modes. MongoDB’s working set memory requirements, Cassandra’s compaction strategies, DynamoDB’s hot partition problems. These are not just operational details. They are entire domains of specialised knowledge.
Your startup probably doesn't need a DynamoDB expert. It needs someone who can write efficient queries, reason about indexes, and track down performance issues. Those skills transfer cleanly across SQL databases. They do not transfer nearly as well to whichever NoSQL solution happened to be fashionable last quarter.
Operational burden is only part of the story though. The deeper cost shows up the moment your system needs to behave correctly under real-world conditions.
The ACID reality check
Let’s talk about transactions. NoSQL advocates often wave away ACID properties as old-fashioned, but data integrity is not a legacy concern. It is a basic requirement.
Imagine you are building a simple e-commerce application. A user places an order. You need to update inventory, charge their card, and create an order record. In a relational database, this is a single, straightforward transaction. If any step fails, everything rolls back and the data stays consistent.
In a NoSQL world, you suddenly find yourself playing the role of a distributed systems expert. You are implementing saga patterns, dealing with partial failures, and writing compensating transactions. A simple business operation turns into a carefully coordinated dance built around eventual consistency.
At this point, the original promise of simplicity starts to feel inverted. You gave up schemas, mature tooling, and transactional guarantees in exchange for flexibility you rarely needed.
So it is worth asking the uncomfortable question. Was this complexity actually worth it? What problem did you solve that justified the extra operational overhead?
The premature optimisation trap
This is where many NoSQL adoptions quietly go wrong. They are premature optimisations, framed as architectural foresight. We worry about hypothetical scale and trade away day-to-day productivity.
SQL gives you compounding wins almost immediately. Need to analyse user behaviour? Write a query. Need a report? JOIN some tables. Chasing down a data inconsistency? Follow the foreign keys. These are not flashy techniques. They are boring, dependable tools that let you spend time on actual product problems.
NoSQL databases shine in specific cases. Time-series data. Systems with genuinely unbounded or unpredictable schemas. Workloads operating at truly massive scale. But most applications are building user accounts, content, or commerce. These are solved problems, and relational databases solve them well.
The path forward
This is not an argument against NoSQL. It is an argument against reaching for it too early.
Choose your database based on the problems you have today, not the ones you might have someday. There is a natural progression to these decisions.
Start with PostgreSQL. Use JSON columns when you need flexibility. Lean on full-text search. Scale it vertically, then horizontally. Push it until it actually starts to hurt.
When you finally hit real limits, you will have evidence. You will understand your access patterns, your bottlenecks, and your failure modes. Only then does it make sense to split workloads or introduce specialised databases, whether that is time-series, graph, vector, or even a distributed document store.
At that point, NoSQL becomes a deliberate tool, not a substitute for learning relational databases properly. That is the difference between informed architecture and borrowed complexity.
Choosing boring technology is often the most pragmatic move you can make. Your users care about features that work. Your future self will care about systems that are easy to reason about. Sometimes the best engineering decision is the one that gets the database out of the way so you can focus on everything else.