Technical

SQL vs NoSQL: Choosing the Right Database

SQL vs NoSQL database selection: relational, document, key-value, and graph databases compared. Learn when to use each for your app.

Dragan Gavrić
Dragan Gavrić Co-Founder & CTO
| · 10 min read
SQL vs NoSQL: Choosing the Right Database

SQL vs. NoSQL: A Practical Guide to Choosing the Right Database

The “SQL vs. NoSQL” framing has always been a bit misleading. It implies a binary choice — pick one camp and commit. In reality, modern applications routinely use multiple database types, each selected for what it does best. The question isn’t “SQL or NoSQL?” It’s “which database type fits which part of my application?”

This guide covers the major database categories, their strengths and trade-offs, when to use each, and how to make decisions you won’t regret in three years.

Foundational Concepts: ACID vs. BASE

Before comparing database types, it’s worth understanding the two consistency models that underpin them.

ACID (Atomicity, Consistency, Isolation, Durability)

ACID is the consistency model used by relational databases. It guarantees:

  • Atomicity. A transaction either completes entirely or not at all. If a bank transfer debits one account, it must credit the other. No partial transactions.
  • Consistency. Every transaction moves the database from one valid state to another. Constraints, foreign keys, and validation rules are always enforced.
  • Isolation. Concurrent transactions don’t interfere with each other. Two users updating the same record simultaneously get predictable results.
  • Durability. Once a transaction is committed, it survives crashes, power failures, and hardware faults. The data is written to persistent storage.

ACID is essential when data correctness is non-negotiable: financial transactions, inventory management, healthcare records, anything where an inconsistency creates real-world consequences.

BASE (Basically Available, Soft state, Eventually consistent)

BASE is the consistency model common in distributed NoSQL systems. It trades strict consistency for availability and performance:

  • Basically Available. The system guarantees availability, even if some nodes are down. You might get stale data, but you’ll get a response.
  • Soft state. The system’s state may change over time, even without new input, as data propagates across nodes.
  • Eventually consistent. If no new updates are made, all nodes will eventually converge to the same state. “Eventually” might be milliseconds or seconds.

BASE is appropriate when availability matters more than instant consistency: social media feeds, product catalogs, analytics data, content delivery.

The Reality

The line between ACID and BASE has blurred. PostgreSQL can handle document-style JSON workloads. MongoDB supports multi-document ACID transactions since version 4.0. CockroachDB offers distributed SQL with ACID guarantees. Choose based on your actual requirements, not on category labels.

Relational Databases (SQL)

Relational databases store data in tables with defined schemas, related through foreign keys. They’ve been the backbone of application development for over four decades.

PostgreSQL

Position: The most versatile open-source database. If you need one database and want to minimize risk, PostgreSQL is the answer.

Strengths:

  • Full ACID compliance with mature transaction support.
  • JSON/JSONB support for document-style data within a relational model.
  • Full-text search capable enough for most applications (though not a replacement for Elasticsearch at scale).
  • Extensions: PostGIS for geospatial, pgvector for AI embeddings, TimescaleDB for time-series, pg_cron for scheduling.
  • Excellent performance with proper indexing. Partial indexes, expression indexes, and covering indexes provide optimization options most developers never exhaust.
  • Strong community. Active development. Not controlled by a single corporation.

Limitations:

  • Write-heavy workloads at extreme scale require careful tuning or sharding solutions (Citus, native partitioning).
  • Vertical scaling hits a ceiling. Horizontal read scaling via replicas is straightforward; horizontal write scaling requires more architecture.

Use when: It’s your default choice. Start here and add specialized databases only when PostgreSQL demonstrably can’t meet a requirement.

MySQL

Position: The world’s most popular open-source relational database by deployment count. Powers WordPress, most PHP applications, and a significant portion of the internet.

Strengths:

  • Extremely mature and well-understood. Performance characteristics are predictable.
  • Read-heavy workload performance is excellent, especially with InnoDB and proper indexing.
  • Replication is straightforward to set up and operate.
  • Wide hosting support. Every cloud provider, every managed database service, every shared host supports MySQL.

Limitations:

  • Fewer advanced features than PostgreSQL (no partial indexes, less capable JSON support, limited window functions in older versions).
  • The Oracle ownership introduces licensing uncertainty for some organizations.
  • The MySQL/MariaDB fork situation adds confusion to the ecosystem.

Use when: Your framework defaults to MySQL (Laravel, many WordPress projects), your team has deep MySQL expertise, or you’re optimizing for hosting availability.

SQL Server

Position: Microsoft’s enterprise database. Dominant in .NET ecosystems and organizations invested in Microsoft infrastructure.

Strengths:

  • Tight integration with Azure, .NET, and Microsoft tooling.
  • SQL Server Analysis Services (SSAS), Reporting Services (SSRS), and Integration Services (SSIS) provide a complete data platform.
  • Enterprise features (Always On availability groups, columnstore indexes, in-memory OLTP) are mature and well-supported.

Limitations:

  • Licensing costs are significant. Enterprise edition runs into tens of thousands of dollars per core.
  • Primarily a Windows ecosystem, though Linux support has improved.
  • Less flexibility than PostgreSQL for non-traditional workloads.

Use when: You’re in a Microsoft shop, building on .NET, or require specific SQL Server enterprise features.

Document Databases

Document databases store data as semi-structured documents (typically JSON). Each document can have a different structure, which provides schema flexibility at the cost of relational integrity.

MongoDB

Position: The most widely adopted NoSQL database. Dominant in the document database category.

Strengths:

  • Natural mapping to application objects. A JavaScript object stored directly as a MongoDB document eliminates ORM friction.
  • Schema flexibility allows rapid iteration. Add fields without migrations.
  • Horizontal scaling via sharding is built into the architecture.
  • Atlas (MongoDB’s managed service) provides a polished cloud experience.
  • Aggregation pipeline is powerful for data transformation and analysis.

Limitations:

  • No foreign keys. Referential integrity is the application’s responsibility. This is fine for some data models and a disaster for others.
  • Multi-document transactions (added in 4.0) work but are not as performant or battle-tested as relational database transactions.
  • Data duplication. Denormalized data models mean updating a piece of information that exists in multiple documents requires updating all of them.
  • Schema-less doesn’t mean schema-free. Without discipline, your database becomes a graveyard of inconsistent document shapes.

Use when: Your data is genuinely document-shaped (CMS content, product catalogs with variable attributes, user profiles with nested structures), you need horizontal write scaling, or your application requires rapid schema evolution.

Don’t use when: Your data is highly relational (orders referencing customers referencing products with inventory), you need complex joins, or data consistency is critical.

CouchDB

Position: A document database designed for offline-first applications and multi-master replication.

Strengths: Built-in HTTP API. Conflict resolution for offline sync. MapReduce views.

Use when: You’re building an application that must work offline and sync when connectivity returns. CouchDB (and its mobile variant, PouchDB) handles this scenario better than almost anything else.

Key-Value Stores

The simplest database type. Store a value, retrieve it by key. No queries, no joins, no schema — just key-value pairs with exceptional performance.

Redis

Position: The dominant in-memory data store. Used primarily as a cache, session store, message broker, and real-time data structure server.

Strengths:

  • Sub-millisecond latency for reads and writes.
  • Rich data structures: strings, hashes, lists, sets, sorted sets, streams, HyperLogLog.
  • Pub/Sub messaging built in.
  • Lua scripting for atomic operations.
  • Redis Stack adds JSON, search, time-series, and graph capabilities.

Limitations:

  • Memory-bound. Your dataset must fit in RAM (or you use Redis on Flash for tiered storage).
  • Not a primary database for most use cases. Data persistence exists (RDB snapshots, AOF logging) but recovery after a crash is slower than a disk-based database.

Use when: Caching (the most common use case), session storage, rate limiting, real-time leaderboards, message queuing, and any scenario where sub-millisecond latency matters.

DynamoDB

Position: Amazon’s fully managed key-value and document database. Designed for applications that need single-digit millisecond performance at any scale.

Strengths:

  • Truly serverless. No capacity planning, no server management. Auto-scales to any traffic level.
  • Single-digit millisecond latency at any scale.
  • Built-in encryption, backup, and point-in-time recovery.

Limitations:

  • Query flexibility is limited. You must design your access patterns upfront. Ad-hoc queries are expensive or impossible.
  • Vendor lock-in. DynamoDB is AWS-only.
  • Cost can escalate quickly with high read/write volumes if not carefully managed (on-demand pricing is convenient but expensive).

Use when: You need a fully managed, auto-scaling key-value store with predictable latency and your application is on AWS.

Wide-Column Stores

Wide-column databases store data in rows and column families, optimized for massive-scale writes and reads across distributed clusters.

Apache Cassandra

Position: The distributed database for write-heavy, globally distributed workloads. Used by Apple (400,000+ nodes), Netflix, Discord, and others at extreme scale.

Strengths:

  • Linear horizontal scaling. Add nodes to increase capacity with no downtime.
  • No single point of failure. Every node is equal in a peer-to-peer architecture.
  • Tunable consistency. Choose between strong and eventual consistency per query.
  • Excellent write throughput. Optimized for high-volume ingest.

Limitations:

  • Query model is restrictive. You must model your data around your queries, not the other way around. Changing access patterns often requires restructuring tables.
  • No joins, no subqueries, limited aggregations. Keep your queries simple.
  • Operational complexity. Running Cassandra well requires expertise.
  • Not suitable for small-scale applications. The overhead isn’t worth it below millions of rows and multiple nodes.

Use when: IoT data ingestion, event logging, time-series at scale, globally distributed applications needing multi-region writes.

ScyllaDB

Position: A Cassandra-compatible database written in C++ for higher performance and lower latency. Drop-in replacement for Cassandra with better resource efficiency.

Use when: You need Cassandra’s data model but want better performance per node and lower operational costs.

Graph Databases

Graph databases model data as nodes and edges (relationships). They excel at queries that traverse relationships — the kind of queries that bring relational databases to their knees.

Neo4j

Position: The dominant graph database. Used for social networks, recommendation engines, fraud detection, knowledge graphs, and network analysis.

Strengths:

  • Cypher query language makes relationship traversal intuitive.
  • Index-free adjacency means relationship lookups are constant time regardless of graph size.
  • Excellent for “friends of friends,” “customers who also bought,” and “shortest path between” queries.

Limitations:

  • Not a general-purpose database. Don’t use it for tabular data that fits naturally in a relational model.
  • Scaling horizontally is more complex than with distributed NoSQL databases.
  • The learning curve for Cypher and graph data modeling is non-trivial.

Use when: Relationships are the core of your data model, not just a way to connect tables. Social networks, recommendation engines, fraud detection, supply chain mapping.

Time-Series Databases

Optimized for data that is indexed by time: metrics, IoT sensor data, financial tick data, application logs.

InfluxDB

Position: The most popular open-source time-series database. Designed for monitoring, IoT, and real-time analytics.

Strengths: Purpose-built storage engine for time-series data. Automatic data compaction and retention policies. Flux query language for time-series analysis.

TimescaleDB

Position: A PostgreSQL extension that adds time-series capabilities. Combines the familiarity of SQL with time-series optimizations.

Strengths: Full SQL support. Runs on PostgreSQL (use your existing tooling, backups, and expertise). Continuous aggregation for real-time materialized views.

Use when: You already use PostgreSQL and need time-series capabilities without adding another database to your stack.

Search Engines

Elasticsearch

Position: The dominant full-text search and analytics engine. Powers search at Wikipedia, GitHub, Stack Overflow, and thousands of other applications.

Strengths:

  • Full-text search with relevance scoring, fuzzy matching, synonyms, and language analysis.
  • Near real-time indexing and search.
  • Aggregation framework for analytics (histograms, percentiles, nested aggregations).
  • Kibana provides out-of-the-box visualization.

Limitations:

  • Not a primary database. Use it as a search index alongside your primary data store.
  • Resource-intensive. Elasticsearch clusters consume significant memory and CPU.
  • Operational complexity. Cluster management, shard allocation, and index lifecycle require attention.

Use when: Your application needs search beyond what PostgreSQL’s full-text search provides: complex relevance tuning, faceted search, typeahead suggestions, or analytics across millions of documents.

Polyglot Persistence: Using Multiple Databases

Most production applications of meaningful complexity use more than one database. This is called polyglot persistence, and it’s a feature, not a problem — as long as it’s intentional.

A common pattern:

  • PostgreSQL as the primary transactional database (source of truth).
  • Redis for caching, session management, and rate limiting.
  • Elasticsearch for search and analytics.
  • S3 (or equivalent object storage) for files and media.

Each database handles what it’s best at. The complexity comes from keeping data synchronized across stores (typically via event-driven updates or change data capture).

When to Add a New Database

Add a specialized database when:

  1. Your primary database demonstrably can’t meet a performance or functionality requirement.
  2. You’ve measured the problem, not just assumed it.
  3. The operational cost of running an additional database is justified by the benefit.

Don’t add a new database because:

  1. You read a blog post about it.
  2. A framework tutorial used it.
  3. It would look good on your architecture diagram.

Every database you add is another system to monitor, back up, scale, secure, and maintain. For many applications, PostgreSQL plus Redis handles 90% of requirements.

Migration Strategies

Changing databases is one of the most disruptive operations in software engineering. When it’s necessary, approach it methodically.

Dual-Write Migration

Write to both the old and new database simultaneously. Once the new database is verified, cut over reads and retire the old one.

Pros: Zero downtime. Reversible. Cons: Complex consistency management during the transition. Both databases must handle production write load.

ETL Migration

Extract data from the old database, transform it to the new schema, and load it into the new database. Cut over during a maintenance window.

Pros: Simpler than dual-write. Clean data transformation. Cons: Requires downtime (or a freeze period). Data that changes during migration needs special handling.

Strangler Fig Pattern

New features write to the new database. Existing features are gradually migrated. The old database shrinks over time until it can be retired.

Pros: Incremental. Low risk per step. No big-bang cutover. Cons: Longer total migration period. Application must handle data in two locations during transition.

Scaling Patterns

Read Replicas

Create read-only copies of your primary database. Route read queries to replicas, write queries to the primary. This works for read-heavy workloads (most web applications are 80-95% reads).

Supported by: PostgreSQL, MySQL, SQL Server, MongoDB, and most managed database services.

Sharding

Distribute data across multiple database instances based on a shard key (e.g., user ID, region, tenant). Each shard holds a subset of the data.

When to shard: When your dataset exceeds what a single server can handle, or when you need write scaling beyond what a single primary can provide.

The hard part: Choosing the right shard key. A bad shard key creates hot spots (uneven data distribution) and makes cross-shard queries expensive. Resharding after the fact is painful.

Partitioning

Divide a table into smaller physical segments based on a column (typically a date or ID range). Queries that filter on the partition key only scan the relevant partition.

Supported by: PostgreSQL (native declarative partitioning), MySQL, SQL Server, and most major databases.

Best for: Time-series data, log tables, and any table that grows continuously and is queried by the partitioning column.

Managed vs. Self-Hosted

Managed Databases (RDS, Cloud SQL, Atlas, PlanetScale)

Pros: Automated backups, patching, scaling, monitoring, and failover. You focus on your application, not your database infrastructure.

Cons: Higher cost (typically 2-3x self-hosted). Less control over configuration. Potential vendor lock-in. Performance tuning options may be limited.

Self-Hosted

Pros: Full control. Lower infrastructure cost. No vendor lock-in. Custom configurations.

Cons: You’re responsible for everything: backups, security patches, failover, monitoring, scaling, and 2 AM pages when the disk fills up.

Practical Recommendation

Use managed databases unless you have a strong reason not to. The cost premium is worth the operational savings for most organizations. The team time you save on database administration is better spent on product development.

Cost Comparison

Database costs come from multiple sources, and the cheapest option depends on your usage pattern:

  • Storage costs dominate for data-heavy, low-query workloads.
  • Compute costs dominate for query-heavy workloads.
  • I/O costs can surprise you on cloud platforms (AWS charges for IOPS on some storage types).
  • Data transfer costs add up when databases communicate across availability zones or regions.

Cost-saving strategies:

  • Use reserved instances or committed use discounts for production databases (30-60% savings).
  • Implement caching (Redis) to reduce read load on the primary database.
  • Archive old data to cheaper storage (S3, Glacier) and keep only active data in the database.
  • Right-size your instances. Many databases run on larger instances than they need.

Making the Decision

If you’re starting a new project:

  1. Start with PostgreSQL as your primary database. It handles relational data, JSON documents, full-text search, and more.
  2. Add Redis when you need caching, session management, or real-time features.
  3. Add Elasticsearch when PostgreSQL’s full-text search can’t meet your search requirements.
  4. Consider a specialized database only when you have a measured performance problem or a use case that fundamentally doesn’t fit the relational model.

The goal isn’t to use the most databases. It’s to use the right databases — as few as possible, each chosen for clear, defensible reasons. Complexity is not a feature. Every database in your architecture is a system your team must understand, operate, and maintain. Choose deliberately.

Share

Ready to Build Your Next Project?

From custom software to AI automation, our team delivers solutions that drive measurable results. Let's discuss your project.

Dragan Gavrić

Dragan Gavrić

Co-Founder & CTO

Co-founder of Notix with deep expertise in software architecture, AI development, and building scalable enterprise solutions.