Choosing a database is one of the most impactful decisions you make in a project.
It affects your application's performance, your monthly bill, and how often your team gets called at night.
When developers discuss databases, the conversation usually starts with product names: PostgreSQL, MongoDB, Redis.
Architects start differently. They first ask questions about the data, the team, and the budget. The product name is the last thing they decide.
Over the past years, I've built and scaled .NET systems using most of the databases on this list. In this post, I'll break down every major database family: what each one is good at, what it really costs, and how to choose the right one for your project.
In this post, we will explore:
- What an architect is actually choosing
- Relational databases: PostgreSQL, MySQL and MariaDB
- Commercial relational: SQL Server and Oracle
- Embedded databases: SQLite
- Document databases: MongoDB and RavenDB
- Key-value and in-memory: Redis
- Wide-column databases: Cassandra
- Managed cloud databases
- Cloud-native databases: DynamoDB and Cosmos DB
- The specialized database families you should know exist
- How to evaluate a database before you commit
- Choosing a database in 2026
Let's dive in.
What an Architect Is Actually Choosing
When you choose a database, you're not just choosing a product.
You're choosing how your system behaves when something fails, who fixes it at night, and how much you pay every month.
Here are 6 questions that decide the choice before any product is named:
1. What shape is the data, and how do you read it? Rows with relationships, documents that you read as a whole, or values fetched by a known key? This question eliminates most of the list, and it's about the shape of your data, not the scale. I covered this split in Getting Started with System Design.
2. What does a wrong answer cost? A stale like count costs nothing. A stale account balance costs money and trust. This answer sets your consistency requirement, and consistency is the most expensive property to guarantee.
3. What is your p99 latency under real load? The p99 is the response time that 99% of requests stay under. The average hides problems, so measure the p99 with your real query mix — that's what your slowest users actually experience.
4. Who supports the database in production? A managed service moves patching, failover and backups to the provider. Self-hosting moves them to your team. Both options are valid; you just need to know which one you're signing up for.
5. What does it cost at twice today's traffic? Consumption-based pricing looks cheap at the start, but it grows with every request. Per-core licensing is predictable, but it gets expensive when you scale out.
6. What does it cost to leave? When you lock in to a specific database, moving to another one can mean a complete application rewrite.
Notice that only the first question is about the database itself. The other five are about your team and your organization.
There is one more question that most teams skip: do you need more than one database engine at all?
Each engine can be better at its own job. Still, each one also adds operational work: backups and restores, a high-availability setup, upgrades, monitoring dashboards, driver maintenance, and people who understand it during an incident. That adds up to weeks of platform work per year, per engine.
Two rules help you keep this under control.
First, nominate one system of record per fact. Every piece of data has exactly one authoritative home, and every other copy is a projection you can throw away and rebuild.
Second, never dual-write. If your application writes to PostgreSQL and to a search index in the same request, one of those writes will eventually fail, and the two stores will silently diverge. Write to the main system of record first, and propagate the change asynchronously through an outbox or change data capture.
Finally, add a new engine only when it's roughly few times better for your workload, not 20% better.
Now let's go through each database family, starting with the most popular one.
Relational Databases: PostgreSQL, MySQL and MariaDB
PostgreSQL is the default choice for most systems, and it's what I recommend to most teams.
It's a relational database that also stores JSON documents, runs full-text search, and handles geospatial queries. That range is the reason most projects never need a second engine.
MySQL and its fork MariaDB solve a narrower problem well: simple, high-throughput reads on a well-indexed schema, with the shortest learning curve of the three.
Strengths:
- One engine covers relational, document, search and geospatial workloads
- Mature query tooling —
pg_stat_statementsshows you which query is slow in seconds - It's easy to hire developers who already know it
Weaknesses:
- One write primary. Read replicas scale reads, but scaling writes means sharding or distributed SQL
- Self-managed failover needs extra tooling; it's not built in
- MySQL lags behind PostgreSQL on window functions, CTEs and richer types
Licensing: PostgreSQL uses the permissive PostgreSQL License and is free for any purpose. MySQL is dual-licensed under GPLv2 or a commercial license, which you need if you bundle it inside closed-source software you distribute. MariaDB Server is GPLv2, though its MaxScale proxy moved to a fully proprietary license in 2025.
Choose it when:
- You're building a line-of-business application and have no measured reason to do otherwise
- Your data has relationships and your reports aren't known in advance
- You want the safest hiring and tooling story available
Commercial Relational: SQL Server and Oracle
SQL Server and Oracle use the same relational model as PostgreSQL and MySQL. The difference is what comes with the license: support contracts, a deep security suite, and high-availability features that the open-source engines make you assemble yourself.
Commercial means the business model. Some of the largest systems in the world run on free engines: YouTube runs on MySQL, and ChatGPT runs on PostgreSQL.
What you're buying here is the vendor relationship.
For .NET teams, SQL Server is a popular choice too.
Strengths:
- The deepest built-in high-availability story: Always On availability groups, Data Guard, RAC
- Security features that ship in the box — Always Encrypted, auditing
- First-class .NET tooling in IDEs
Weaknesses:
- Per-core licensing makes horizontal scaling expensive — every new box adds to the bill
- The best features are only available in the top edition
- Oracle expertise is rare and expensive, and license renewals are hard to negotiate
Licensing: SQL Server Express is free but capped at a 10 GB database, 1,410 MB of buffer pool and 4 cores. Developer edition is free and has every Enterprise feature, but it's licensed for development and testing only, never production — see the editions comparison.
Note that Always On availability groups are Enterprise-only; Standard edition gets a two-replica basic version.
Oracle Database Free allows 12 GB of user data, 2 GB of RAM and 2 cores, but it receives no patches at all, including security patches. Use it only as a development tool, which is not suitable for production.
Choose it when:
- Your company already uses Microsoft or Oracle products and has already paid for the licenses
- You need certified high availability and auditing without assembling them yourself
- Your compliance requirements expect a vendor with a support contract
Embedded Databases: SQLite
Many developers treat SQLite as a toy database (or only for tests). It's not.
SQLite is a full relational engine that runs inside your process and stores everything in a single file. There is no server, no port, no connection pool, and nothing to operate.
It's the most widely deployed database in the world — it runs inside every phone, browser and operating system.
Strengths:
- Zero operational cost — no server to patch, monitor, or fail over
- Extremely fast local reads, with no network hop or serialization
- A great fit for desktop, mobile, edge, embedded devices and test suites
- Supports multiple writers at a time using WAL
Weaknesses:
- Multiple writers can slow things down
- No network access, so a second machine can't share the data
- No built-in replication, users, or role-based security
Licensing: SQLite is in the public domain with no restrictions at all. You can optionally buy a Warranty of Title for jurisdictions that don't recognize public domain dedication, plus commercial support.
Choose it when:
- The application runs on one machine and owns its own data
- You're shipping desktop, mobile or edge software
Document Databases: MongoDB and RavenDB
A document database stores an entity as a single nested object. Instead of joining six tables to assemble an order, you read the whole document by its ID.
This model works great when your read pattern really is "fetch this entity by its id".
MongoDB has the larger ecosystem and the managed Atlas service. It also supports multi-document ACID transactions since version 4.0, so choosing a document database doesn't mean giving up transactional writes.
RavenDB deserves special attention from .NET developers: it's ACID by default across documents, it builds indexes automatically, and its client library is built for .NET.
Strengths:
- Flexible schema — documents in one collection can differ in shape
- One read returns the whole entity, with no joins to assemble it
- Horizontal sharding is designed and much easier than in a relational database
Weaknesses:
- Joins are limited or move into your application code
- Ad-hoc reporting is weaker than SQL, so analytics usually move to another store
- Without discipline, a flexible schema becomes an undocumented schema
Licensing: MongoDB Community is free under the SSPL, which restricts offering MongoDB itself as a service but explicitly permits embedding it in your own commercial product. Atlas has a free M0 tier capped at 512 MB and roughly 100 operations per second.
RavenDB Community is free and permitted for commercial use, but the cluster is capped at 3 nodes, 3 cores and 6 GB of RAM — check that limit against your workload before committing.
Choose it when:
- Your entities are naturally nested and read as a unit
- Attributes legitimately vary per record, as in a multi-category catalog
- You have a high volume of write operations
Key-Value and In-Memory: Redis
Redis is an in-memory key-value store.
It keeps all the data in RAM and returns values by key in under a millisecond. That speed is the main reason to use it — and it's also the source of every Redis limitation, because RAM is expensive and doesn't survive a restart.
Redis works great as a cache. Problems start when teams use it as the primary storage for data they can't afford to lose.
Strengths:
- Sub-millisecond reads at very high throughput
- Useful data structures beyond strings — counters, sorted sets, streams, TTLs
- A natural home for sessions, carts, rate limits and leaderboards
Weaknesses:
- The whole dataset must fit in RAM, and RAM is the most expensive storage tier
- Durability is limited to snapshots and an append-only log; there is no real point-in-time recovery
- Failover is fast but can lose recent writes, so treat everything in Redis as rebuildable
Licensing: Redis licensing depends on the version:
- Redis 7.2 and earlier are BSD-3-Clause.
- Versions 7.4 to 7.8 are RSALv2 or SSPLv1.
- Redis 8.0 and later add AGPLv3 as a third option — see Redis licensing.
Choose it when:
- You need a cache, and losing the whole thing is not a big deal
- You need counters, rate limits or leaderboards that would strain a relational database
- Sessions must be shared across a horizontally scaled application tier
Wide-Column Databases: Cassandra
Cassandra is designed for one job: handling a massive stream of writes across many machines.
It has no primary node. Any node can accept a write, which is why the cluster survives losing machines and can span multiple regions.
The trade-off is in the queries. In Cassandra, you design a separate table for each query pattern. If a question arrives that you didn't plan a table for, you can't just write a different WHERE clause — the query is effectively unavailable.
Strengths:
- Millions of time-ordered writes across a cluster, with linear scaling
- No single point of failure and no failover event to survive
- Multi-region replication is built into the data model
Weaknesses:
- Query patterns must be known up front; ad-hoc queries aren't practical
- It's famously hard to debug when it misbehaves, and expertise is rare
- You need a three-node minimum plus people who can run it, before you store a single row
Licensing: Apache Cassandra is Apache License 2.0, fully free with no paid tier from the project itself.
Choose it when:
- Your write volume genuinely exceeds what a single relational primary can handle
- Your access pattern is narrow, known in advance, and time-ordered
- You need multi-region writes without a leader node
One caution from practice: most teams that reach for Cassandra don't actually write at a rate that needs it. A well-indexed PostgreSQL or MongoDB primary handles far more write traffic than most people assume.
Managed Cloud Databases
A managed database isn't a separate data model — it's a different way to run the engines we've already covered.
Amazon RDS and Aurora, Azure SQL Database, Google Cloud SQL, MongoDB Atlas, DynamoDB and Cosmos DB all run a familiar engine and take over the parts most teams do badly: patching, backups, failover, and monitoring.
The engine stays the same. What changes is who does the work.
DynamoDB and Cosmos DB share these benefits too.
What the provider takes: operating system and engine patching, automated backups with point-in-time restore, replica provisioning and failover, and hardware failures.
What stays yours: schema design, query performance, indexing, capacity choices, connection limits, and the bill.
Strengths:
- Backups, point-in-time restore and failover work on day one
- Scaling up is a configuration change, not a maintenance window
- You keep the engine and its ecosystem, so the exit cost stays low
Weaknesses:
- You pay more than for a raw VM — you're paying the provider to handle operations
- Superuser access and some extensions are restricted
- Version upgrades happen on the provider's schedule, not yours
Choose it when:
- Your team is small enough that database operations isn't a full-time role
- You need a credible backup and failover story without building one
- You want a known engine with the boring parts outsourced
For most teams, this is the right default. A managed PostgreSQL costs more per month than a self-hosted VM, but it's cheaper than one serious incident caused by a missed backup or a failed manual failover.
Cloud-Native Databases: DynamoDB and Cosmos DB
DynamoDB and Cosmos DB are fully managed NoSQL databases from AWS and Azure. You don't install or patch anything — you pay for throughput and storage.
They give you single-digit millisecond reads at almost any scale, with no servers to manage. In exchange, you design your data around the provider's model, and leaving later means rewriting your data access layer.
The most expensive mistake in both databases is a bad partition key. The partition key decides how your data spreads across storage nodes — a bad one concentrates traffic on a single "hot" partition and multiplies your bill.
Strengths:
- Predictable low latency at any scale, with no capacity planning
- Operations are entirely the provider's problem
- Turnkey multi-region replication, which is genuinely hard to build yourself
Weaknesses:
- Access patterns must be designed up front and are expensive to change later
- A hot partition or an accidental full scan makes a cheap table expensive
- The deepest lock-in on this list — a proprietary API, not portable SQL
Licensing: Both are consumption-priced. DynamoDB bills per request or per provisioned capacity, with a free tier of 25 read and 25 write capacity units plus 25 GB.
Cosmos DB bills Request Units per second, per region — a poor partition key multiplies that across every region you run in.
Choose it when:
- Access is by a known key and the patterns are stable
- You're already committed to one cloud and want zero database management operations
- You need global distribution without building replication yourself
The Specialized Database Families You Should Know Exist
Four more database families are worth knowing, so you can recognize when your problem needs a specialized engine:
- Search engines (Elasticsearch, OpenSearch) — full-text relevance, faceting and typo tolerance.
- Graph databases (Neo4j) — traversals across relationships, like "customers who bought this also bought", where SQL joins grow exponentially.
- Time-series databases (TimescaleDB, InfluxDB) — append-heavy metrics with time-bucketed rollups and automatic retention.
- Vector databases (pgvector, MongoDB Vector, Pinecone, Qdrant) — similarity search over embeddings for semantic search and retrieval-augmented generation.
Each of them is genuinely better at its job than a general-purpose engine. Each of them is also one more engine to back up, monitor, upgrade and staff.
How to Evaluate a Database Before You Commit
Evaluating a new database is a risk assessment.
The real question is what happens to your data, your team and your production system when the database misbehaves under your workload.
Here are 6 checks to run, in order. Stop at the first one that fails.
1. Workload fit. Write down your access patterns, consistency requirements and the scale you expect two years from now. If your current database with a redesigned index or a cache in front of it handles that, it might be a good fit.
2. Benchmark with your data and your queries. Vendor benchmarks measure the vendor's best case. Run production-shaped data at production volume with your real query mix, at two to five times the expected peak, and measure the p99. Include the write path under concurrent reads — many stores look great on read benchmarks and fall apart under mixed load.
3. Break it on purpose. Kill a node in the middle of a write and watch what happens: a clean failover, or silent data loss? Then run a full backup and a full restore, and time the restore.
4. Operational maturity. How do upgrades work — rolling, or with downtime? What does the built-in observability actually show you? This is where engines differ sharply: PostgreSQL and SQL Server have decades of query tooling, while some stores are great when healthy and impossible to inspect when sick. Ask yourself how long it would take to find a slow query during an incident.
5. Ecosystem and team. Is the .NET driver first-class, or a community project two versions behind? Can you hire people for it, and is there more than one person on the team willing to own it? If only one engineer understands the database, you have a problem waiting to happen the day they leave.
6. Exit cost. Estimate the migration out before you migrate in. Databases with standard protocols and export formats are cheap to leave. A proprietary API means a costly rewrite.
Three red flags cancel all of the above:
- Marketing that claims the database handles all workloads equally well. Every storage engine has trade-offs; universal claims mean the trade-offs aren't stated.
- Benchmarks that quote only average latency, or run on datasets that fit entirely in RAM.
- You're excited by the technology rather than blocked by an actual problem.
Default to boring technology. Well-known databases have failure modes that are documented by years of other people's incidents. Adopt a new engine only when a measured workload genuinely defeats the one you already have.
Choosing a Database in 2026
Here is the whole decision as a flowchart:
The tables below compare the same engines across the dimensions that matter in practice: cost, availability, performance, security and hiring.
Cost and Licensing
| Database | What you pay for | The cost trap |
|---|---|---|
| PostgreSQL | Free and open-source | DBA time, or the managed-service premium |
| MySQL / MariaDB | Free under GPLv2 | Bundling MySQL in closed-source software needs a commercial license |
| SQL Server | Per-core, or server plus CAL | Core licensing on a large VM can cost more than the VM itself |
| Oracle | Per-core with a core-factor table | Audits, and key features are licensed separately |
| SQLite | Free, public domain | None — its limits are technical, not financial |
| MongoDB | Community free; Atlas and Enterprise paid | SSPL blocks offering MongoDB itself as a service |
| RavenDB | Free Community tier; paid above it | The free tier caps cores, RAM and cluster size |
| Redis | Depends on the version; Valkey is BSD | Versions 7.4 to 7.8 are source-available, not open source |
| Cassandra | Free, Apache 2.0 | Three-node minimum plus people who can run it |
| DynamoDB | Per request, or provisioned capacity | A hot partition or a full scan makes a cheap table expensive |
| Cosmos DB | Request Units per second, per region | RU/s billed per region; a bad partition key multiplies it |
Availability and Operations
| Database | High availability | Restore and PITR |
|---|---|---|
| PostgreSQL | Streaming replicas; failover needs extra tooling | WAL archiving gives PITR, but you build and test it yourself |
| MySQL / MariaDB | Async or semi-sync replicas; Galera | Binlog PITR; restore time grows with data size |
| SQL Server | Always On, built in — but Enterprise only | Full plus log backups; PITR to the second |
| Oracle | Data Guard and RAC — the strongest on this list | RMAN and Flashback; excellent but expensive |
| SQLite | None — one file, one process | Backup is copying the file |
| MongoDB | Replica sets with automatic election | Atlas gives continuous PITR; self-hosted is manual |
| RavenDB | Multi-master cluster, built in | Built-in backup and point-in-time restore |
| Redis | Sentinel or Cluster; failover is fast but can lose writes | Snapshots and append log only; treat data as rebuildable |
| Cassandra | No leader; survives node loss by design | Snapshot plus commitlog; restore is manual |
| DynamoDB | Multi-AZ by default; Global Tables across regions | PITR from 1 to 35 days, enabled with one switch |
| Cosmos DB | Turnkey multi-region, five consistency levels | PITR tiers of 7, 30 or 35 days; restore is always billed |
Performance and Features
| Database | Fastest at | Falls over when |
|---|---|---|
| PostgreSQL | Mixed workloads with joins, JSON, search and geospatial | Write volume outgrows one primary and you must shard |
| MySQL / MariaDB | Simple high-QPS reads on a well-indexed schema | Queries need window functions, CTEs or richer types |
| SQL Server | Complex T-SQL, and analytics beside transactions | License costs become a problem before performance does |
| Oracle | Enormous single-instance workloads, deeply tuned | License renewal costs outgrow the value it delivers |
| SQLite | Local reads — millions of them, with zero latency | A second writer appears, or a second machine |
| MongoDB | Reading a whole nested entity by id or by field | You need joins, or the working set outgrows RAM |
| RavenDB | Document reads with automatic indexes and ACID writes | You need a large hiring pool or a big ecosystem |
| Redis | Sub-millisecond key lookups at very high throughput | The dataset outgrows RAM, or you need durability |
| Cassandra | Millions of time-ordered writes across many nodes | A query arrives that you didn't design a table for |
| DynamoDB | Key lookups at single-digit ms, at any scale | Access patterns change after the keys are designed |
| Cosmos DB | Global reads and writes with tunable consistency | Throughput rises, and the RU bill rises with it |
Security, Lock-In and Hiring
| Database | Security baseline | Exit cost | Talent |
|---|---|---|---|
| PostgreSQL | Row-level security, TLS, encryption via provider | Low — standard SQL | Everywhere |
| MySQL / MariaDB | Roles, TLS, encryption in enterprise builds | Low — dump and restore | Everywhere |
| SQL Server | RLS, Always Encrypted, TDE, auditing | Medium — T-SQL dialect | Everywhere in .NET |
| Oracle | The deepest on this list | High — PL/SQL rewrite | Rare and expensive |
| SQLite | None — file permissions are the model | None | Everywhere |
| MongoDB | RBAC, TLS, field-level encryption | Low — JSON export | Widely available |
| RavenDB | Certificate-only auth, encryption at rest | Medium — JSON export | Rare |
| Redis | ACLs and TLS, but often deployed unsecured | None — it's a cache | Widely available |
| Cassandra | Roles, TLS, encryption at rest | Medium — CQL is portable | Rare |
| DynamoDB | IAM-native, KMS, fine-grained access | High — proprietary API | Rare outside AWS |
| Cosmos DB | Entra ID, RBAC, customer-managed keys | High — proprietary model | Rare outside Azure |
The Decision Table
| Your workload | Start here | Move on only if |
|---|---|---|
| A .NET line-of-business application | PostgreSQL or SQL Server | Almost never — add a cache first |
| You already own Microsoft licenses | SQL Server, or Azure SQL managed | License cost beats migration cost |
| Nested entities read as a unit | PostgreSQL with JSON columns | Documents need their own indexes and scale |
| Catalogs and profiles at scale | MongoDB or RavenDB | Joins and reporting dominate your queries |
| Sessions, carts, rate limits | Redis or Valkey | You need durability — then it's not a cache anymore |
| Millions of time-ordered writes | Cassandra | A single primary already keeps up |
| Serverless on one cloud, key access | DynamoDB or Cosmos DB | Your access patterns are still changing |
| Desktop, mobile or edge | SQLite | Two machines need the same data |
My Recommendation for 2026
Start with PostgreSQL, or with SQL Server if your company already owns the licenses.
Add a Redis cache when reads become your bottleneck (fix your slow database queries first).
If you want a great NoSQL database as a starting point, select MongoDB.
Add a second database engine only when a measured workload defeats the first one by roughly 10x — and never because the architecture diagram looks better with it.
Use a managed service unless someone on your team is dedicated to database operations.
This path isn't exciting, but it's the right one for most projects.
Summary
Let's recap the key takeaways:
- You're choosing trade-offs. The shape of your data eliminates most of the list. The rest is decided by your team, your budget, and the cost of leaving.
- One engine goes further than most teams think. PostgreSQL with JSON, full-text search and a cache covers a huge range of workloads. ChatGPT with millions of users runs on PostgreSQL.
- Keep one system of record per fact, and never dual-write. Write to the authoritative store and propagate changes asynchronously; otherwise your copies will silently diverge.
- Free has limits. SQL Server Express stops at 10 GB, Oracle Free ships no security patches, RavenDB Community caps at 3 cores. Read the actual license terms before you commit.
- A backup you have never restored is not a backup. Test the restore and measure how long it takes before you go to production, not after an incident.
- Boring technology wins. Well-known databases have well-known failure modes. Adopt a new engine only when a measured workload defeats the current one.
There is no single correct database for every project; you need to pick whatever works best in your particular case — and understand its trade-offs before you commit.
I am building a deep-dive System Design course that goes far past this list.
It will be better than anything you have seen so far:
- Reading
- Watching videos
- Designing real systems in the browser
- Taking tests
Join the waitlist here to get early access and a launch discount.
Hope you find this newsletter useful. See you next time.


Comments