the architecture decision for growing databases
Scale-up and scale-out solve different problems, yet they are often treated as interchangeable options. Vertical scaling means more power for a single instance, horizontal scaling means more instances for the same load. Get this decision wrong and you either build an unnecessarily complex distributed system or hit a hard capacity limit sooner than necessary.
Table of Contents
- 1. Two fundamentally different scaling strategies
- 2. Vertical scaling: limits and benefits
- 3. Horizontal scaling: sharding and distribution
- 4. Choosing the shard key as a critical decision
- 5. What horizontal scaling costs in complexity
- 6. Hybrid strategies: scaling in stages
- 7. Signs that vertical scaling is no longer enough
- 8. Planning a migration from vertical to horizontal
- 9. Vertical and horizontal scaling compared
- 10. Summary
- 11. FAQ
1. Two fundamentally different scaling strategies
Vertical scaling, also called scale-up, increases the capacity of a single database instance through more CPU cores, more memory, or faster disks. Horizontal scaling, also called scale-out, distributes data and load across multiple instances, typically through sharding or partitioning. Both strategies address growing load, but in fundamentally different ways, with different costs and levels of complexity.
The decisive difference lies in architectural complexity. Vertical scaling requires no change to the data model, application logic, or query structure, it is essentially a hardware upgrade. Horizontal scaling, on the other hand, fundamentally changes how data is stored and queried: joins across shard boundaries become expensive or impossible, transactions across multiple shards require additional coordination, and the application needs to know which shard holds a given record.
A common misjudgment is introducing horizontal scaling early because it is seen as more modern or more future proof. In practice, well sized vertical scaling fully resolves the load problems of most small and mid sized applications, at far lower complexity. The decision should be based on actual bottlenecks, not on the assumption that distributed systems always scale better.
2. Vertical scaling: limits and benefits
The biggest advantage of vertical scaling is its simplicity. A larger server with more RAM lets the database keep a larger share of the active dataset in memory, reducing disk access and lowering latency. More CPU cores allow more parallel queries without touching application code or the data model. For many applications, upgrading to a larger instance is the fastest and lowest risk fix for performance problems.
The limit of vertical scaling is both physical and economic. There is a maximum instance size that a cloud provider or the available hardware can even offer, and costs for high end instances rise disproportionately relative to the gained performance. A server with twice the cores often costs more than twice as much, while the actual performance gain falls short of the theoretical factor due to context switching overhead and memory bandwidth limits.
Another structural drawback: vertical scaling does not improve availability. A single, however powerful, server remains a single point of failure. If that one instance fails, the entire database stops, regardless of how much performance it had. Availability additionally requires replication, independent of the question of vertical or horizontal scaling of capacity itself.
-- Example: check resource consumption before scaling vertically
-- PostgreSQL: cache hit ratio as an indicator of RAM demand
SELECT
sum(heap_blks_hit) / nullif(sum(heap_blks_hit) + sum(heap_blks_read), 0) AS cache_hit_ratio
FROM pg_statio_user_tables;
-- Values below 0.99 point to insufficient RAM for the active dataset
-- Active connections and their CPU relevant states
SELECT state, count(*), avg(extract(epoch FROM (now() - query_start))) AS avg_runtime_seconds
FROM pg_stat_activity
WHERE state != 'idle'
GROUP BY state;
3. Horizontal scaling: sharding and distribution
Horizontal scaling distributes data across multiple independent database instances, called shards. Each shard holds a subset of the total data, typically split by a shard key such as customer ID or geographic region. Unlike read replicas, which are complete copies of the same data, each shard owns an independent, non redundant piece of the overall dataset, meaning both write load and storage volume are genuinely distributed.
The fundamental advantage is theoretically unlimited scalability: new shards can be added as data volume grows, without a single instance having to carry the entire load. Large applications with multiple terabytes of data and high write load, which would overwhelm even the largest available single instance, cannot avoid horizontal scaling.
This scalability comes at a price: the application needs to know which shard is responsible for which request, usually through a routing layer that extracts the shard key from the request. Queries that need to combine data from multiple shards, for example for global reports, require either expensive fan-out queries across all shards or a separate analytics system that consolidates data from all shards.
4. Choosing the shard key as a critical decision
Choosing the shard key is the most important and hardest to reverse decision in horizontal scaling. A good shard key distributes load and data volume evenly across all shards and matches the application's most common access patterns. Customer ID often works well for multi tenant applications, because most requests are already scoped to a single customer's data and therefore hit a single shard.
A poorly chosen shard key leads to so called hot shards: individual shards carrying significantly more load than others because the chosen key distributes data unevenly. One example is using a monotonically increasing timestamp as a shard key: all new writes then consistently land on the same, most recent shard, while older shards receive almost no load, a pattern that undermines the entire idea of load distribution.
Changing an existing shard key after going live is expensive and risky, because it effectively means a complete redistribution of all data, often while the system keeps running. That is why it pays off to carefully think through the shard key choice early, based on expected access patterns, rather than treating it as a technical detail that can be easily fixed later.
-- Example: shard assignment via hashing the shard key
-- (pseudo logic, as commonly found in an application router)
-- Good shard key: even distribution through hashing
-- shard_id = hash(customer_id) % number_of_shards
-- Bad shard key: monotonically increasing values create hot shards
-- shard_id = created_at_timestamp % number_of_shards -- NOT recommended
-- Query that hits a single shard (ideal)
SELECT * FROM orders WHERE customer_id = 48213;
-- Query that must hit all shards (fan-out, expensive)
SELECT count(*) FROM orders WHERE status = 'pending';
5. What horizontal scaling costs in complexity
Joins across shard boundaries are the most expensive side effect of horizontal scaling. A single SQL join, a single efficient operation in a non sharded database, becomes either impossible or requires the application to load data from multiple shards and merge it in application code when data is sharded. That shifts logic that really belongs in the database into the application layer, with corresponding maintenance cost.
Transactions spanning multiple shards are another structural problem: classic ACID transactions only work reliably within a single shard. Operations that need to atomically change multiple shards require distributed transaction patterns such as two phase commit or the saga pattern, both with their own complexity and failure costs that simply would not exist in a non sharded database.
Schema changes need to run consistently across all shards under horizontal scaling, which makes migrations significantly more involved than for a single instance. A failed migration script on one of twenty shards leaves an inconsistent overall system that has to be manually detected and fixed, a risk that does not exist for a single instance.
6. Hybrid strategies: scaling in stages
In practice, the decision is rarely binary. A sensible order is to first push vertical scaling to its economic and technical limit, supplemented by read replicas for read traffic, before even considering horizontal scaling. This combination covers a surprisingly large share of real world load profiles without taking on the complexity of sharding.
Partitioning within a single instance is an often overlooked intermediate step: table partitioning by date or category physically distributes data across multiple storage areas within the same database instance, without introducing the complexity of a true distributed system with shard routing. This significantly improves query performance for large tables while architecturally remaining a single, vertically scaled instance.
Only once write load or data volume actually exceed the technical limits of a single, well sized instance does the leap to true horizontal scaling with sharding become justified. This staged approach avoids a team carrying the complexity costs of distributed systems without actually having the corresponding scaling need.
7. Signs that vertical scaling is no longer enough
A reliable signal is when the next larger available instance size no longer produces a proportional performance gain, because bottlenecks are no longer CPU or RAM but structurally tied to the number of simultaneous writes a single instance can physically process. This plateau typically shows up first under write load, less often under pure read traffic, which can usually still be absorbed with read replicas.
A second sign is sheer data volume: when the entire active dataset no longer fits in memory even with the maximum available RAM, and disk access becomes the dominant factor, further vertical scaling only helps to a limited extent. Beyond several terabytes of active, frequently queried data, this point becomes relevant for many workloads.
A third, often underestimated signal is backup and maintenance time: backups, index builds, or large schema migrations on a very large single instance take proportionally longer and increasingly block operations. When maintenance windows become impractically long due to the sheer size of a single instance, that is an indirect but clear indication that horizontal scaling should be seriously evaluated.
8. Planning a migration from vertical to horizontal
Migrating from a single, vertically scaled instance to a sharded system should never happen as a big bang cutover. The proven approach is to first write new data according to the planned shard scheme, while migrating existing data gradually in the background, often over weeks or months, with continuous validation of data consistency between the old and new system.
Feature flags and dual write strategies allow individual parts of the application to move to the sharded system step by step, while other parts continue using the old, unsharded instance. This gradual transition significantly reduces the risk of a complete outage but extends migration time and requires both systems to keep functioning correctly in parallel during the transition.
It is important to thoroughly test the chosen shard key against real production data before starting the migration, rather than discovering it causes hot shards only after the migration. A test migration with a representative copy of production data on a smaller cluster surfaces such problems early, before they need to be expensively corrected in production.
9. Vertical and horizontal scaling compared
The table below compares the key decision criteria between vertical and horizontal scaling and helps identify the fitting strategy for a given use case.
| Criterion | Vertical Scaling | Horizontal Scaling | Practical Recommendation |
|---|---|---|---|
| Implementation effort | Low, usually just a hardware upgrade | High, requires shard routing and adjustments | Push vertical first |
| Maximum capacity | Limited by largest available instance | Theoretically unlimited via more shards | Horizontal once actual data limits hit |
| Joins and transactions | Fully supported, no restrictions | Costly or impossible across shard boundaries | Choose shard key by access patterns |
| Cost curve | Disproportionate at very large instances | Roughly linear per additional shard | Model costs against expected growth |
| Migration risk | Minimal, usually no application changes | High, shard key mistakes hard to fix | Test shard key against real data first |
| Backup and maintenance windows | Grow proportionally with instance size | Small per shard, parallelizable overall | Use maintenance windows as an early signal |
| Team know how | Little extra specialized knowledge needed | Requires experience with distributed systems | Introduce complexity only when truly needed |
| Multi-region availability | Only possible through additional replication | Shards can be distributed regionally | Evaluate horizontal for global user bases |
In practice, most applications get by significantly longer than teams initially expect with carefully sized vertical scaling combined with read replicas. The step to true horizontal scaling pays off only once concrete, measured bottlenecks prove the need, not because of a general assumption about future growth.
Mironsoft
Database architecture and scaling strategy
Not sure which scaling strategy fits?
We analyze your actual bottlenecks, evaluate vertical options realistically, and plan sharding only where it is genuinely needed instead of introducing complexity without cause.
Bottleneck analysis
Measure and evaluate CPU, RAM, I/O and write load separately
Shard key design
Test distribution patterns against real production data upfront
Migration plan
Design a gradual cutover without big bang risk
10. Summary
The choice between vertical and horizontal scaling is not a matter of trend, but a matter of actual bottlenecks. Vertical scaling is simple, low risk, and covers a surprisingly large share of real world load profiles, but it hits physical and economic limits. Horizontal scaling breaks through these limits, at the cost of substantial complexity in joins, transactions, and schema migrations.
Choosing the shard key is the most critical single decision in horizontal scaling and should be tested early against real access patterns, because a later correction is expensive and risky. A staged approach, pushing vertical scaling and read replicas first, then scaling horizontally in a targeted way, avoids unnecessary complexity and keeps the architecture manageable for as long as possible.
Vertical vs. Horizontal Scaling: The Key Points at a Glance
Vertical scaling
Simple, low risk, but limited by maximum instance size and disproportionate costs at the top end.
Horizontal scaling
Theoretically unlimited, but costs complexity in joins, transactions, and schema migrations across shards.
Shard key choice
The most critical decision. A bad choice creates hot shards and is expensive to fix later.
Recommended order
Scale vertically and use read replicas before introducing sharding based on measured bottlenecks.