A deep architectural comparison of Citus, Multigres, and manual sharding for horizontal scaling in PostgreSQL. Learn how to scale your database without hitting the Postgres cliff.

We have all been there. Your application is growing, traffic is spiking, and your database server is running hot. For years, the standard playbook for scaling a relational database was simple: buy a bigger machine. You added more CPU cores, packed in more RAM, and upgraded to ultra-fast solid state drives (SSDs). But eventually, every scaling team hits what we call the Postgres Cliff.
This is the exact point where vertical scaling (upgrading a single server) stops working, either because you have maxed out the largest available cloud instance or because the cost of that giant machine has become unsustainable. When that happens, you have to look at horizontal scaling, which means distributing your database workload across multiple physical servers.
In early 2026, OpenAI published a detailed engineering post on scaling PostgreSQL to power 800 million ChatGPT users. Their team managed to scale a single-primary architecture using nearly 50 read replicas globally. However, they openly shared that they had to migrate their write-heavy, shardable workloads to sharded systems to reduce write pressure on the primary database.
For most growing SaaS, fintech, and e-commerce platforms, managing 50 manual replicas is an operational nightmare. That is why developers are turning to automated horizontal scaling in PostgreSQL.
In this architectural deep dive, we will compare the three primary paths for scaling PostgreSQL horizontally: Citus (the battle-tested extension), Multigres (the new Vitess-inspired operating system for Postgres), and manual application-level sharding. We will examine how they work, how they handle connection pooling, and how to choose the right strategy for your engineering pipeline.
The best way to horizontally scale PostgreSQL depends on your workload: use Citus for multi-tenant SaaS and real-time analytics where you can shard by tenant ID, use Multigres for globally distributed systems requiring Vitess-grade connection pooling and transparent query routing, and use manual sharding only if your application logic can handle complex routing natively.
Before we evaluate the horizontal scaling tools, we need to understand why a single PostgreSQL instance eventually fails under heavy write loads. It is not a limitation of the database itself. Postgres is incredibly well built, but it is bound by the laws of hardware and its own architectural design.
The first major bottleneck is connection management. PostgreSQL uses a process-based connection model. This means that every single client connection spawns a dedicated operating system process on the database server. Each of these processes consumes roughly five to ten megabytes of RAM. When you have thousands of concurrent application containers (like serverless functions or microservices) connecting directly to your database, you quickly run out of memory just maintaining those idle connections.
The second bottleneck is write amplification caused by MVCC (Multi-Version Concurrency Control), the mechanism Postgres uses to handle concurrent transactions safely. When you update a row in Postgres, the database does not overwrite the existing data. Instead, it writes a completely new version of the row (a tuple) to disk and marks the old one as dead.
These dead tuples must eventually be cleaned up by the autovacuum process. Under intense write pressure, the autovacuum cannot keep up, leading to table bloat, fragmented indexes, and massive disk I/O (Input/Output) bottlenecks.
7 in 10 teams we onboard inherit an untested database scaling strategy that relies solely on vertical upgrades.
When your write volume exceeds the throughput of a single primary disk controller, read replicas cannot save you. Replicas are excellent for offloading read-heavy workloads, but every single write must still go through the single primary node. When that primary node hits 100% CPU or disk write saturation, your entire platform slows to a crawl. This is the exact moment you must transition from a single-node system to a sharded PostgreSQL database.
Before you take the leap into a distributed database architecture, you should exhaust the standard, less complex scaling options. Sharding introduces significant network latency, query planning limitations, and operational overhead. In our tech partnership and consultation work, we always advise clients to follow a progressive scaling path.
First, ensure your database configuration is fully tuned. The default Postgres configuration is notoriously conservative, designed to run on almost any hardware. You must tune parameters like shared_buffers (which dictates how much memory Postgres uses for caching data), work_mem (for sorting operations), and max_connections to match your actual hardware.
Second, implement a dedicated connection pooler like PgBouncer. Connection poolers sit between your application and your database, routing thousands of application connections into a tiny pool of heavy, reusable database connections. This prevents the process-allocation memory bottleneck we discussed earlier.
Third, utilize native table partitioning. This is not horizontal scaling, but rather vertical partitioning on a single disk. By breaking a massive, multi-gigabyte table (like an audit log or transaction history) into smaller, physical sub-tables based on a key like a date range, you allow Postgres to perform partition pruning. This means the query planner can ignore entire sections of disk, drastically speeding up queries and vacuum operations.
Finally, set up read replicas. If 90% of your database traffic is read-heavy (such as fetching user profiles or displaying product listings), routing those queries to replicas keeps your primary node free to handle writes. Only when your writes saturate the primary node, or your dataset exceeds the storage capacity of a single machine, should you begin planning a distributed sharding strategy.
Citus is the most mature and widely adopted horizontal scaling solution for PostgreSQL. Originally developed by Citus Data and later acquired by Microsoft, it is built as an extension rather than a fork. This is a critical distinction. Because Citus is an extension, you retain 100% compatibility with standard Postgres features, tools, and third-party extensions like PostGIS or pgvector.
Citus works by transforming a group of PostgreSQL servers into a single, coordinated cluster. The cluster consists of a coordinator node and multiple worker nodes. The coordinator node is the entry point for your application. It receives SQL queries, parses them, creates a distributed execution plan, and parallelizes the queries across the worker nodes where the actual data resides.
The magic of Citus lies in how it shards your tables. You define a distribution column (also known as a sharding key). For example, in a multi-tenant SaaS application, this would be your tenant_id or company_id. Citus then uses hash-based sharding to distribute the rows across virtual shards, which are distributed across the physical worker nodes.
With the release of Citus 14, which supports PostgreSQL 18, Citus introduced several major performance improvements. These include faster distributed scans via asynchronous I/O (AIO), better index usage with skip-scans, and full support for new SQL features like JSON_TABLE.
Citus 14 also supports schema-based sharding (originally introduced in Citus 12). Instead of distributing a single table by a row-level key, schema-based sharding allows you to distribute entire schemas across different worker nodes. This is incredibly useful for legacy applications where rewriting all your SQL queries to include a distribution key is too expensive or time-consuming.
When building custom software development projects for multi-tenant platforms, we frequently recommend Citus because it keeps tenant data colocated. If you join two tables that are both sharded by tenant_id, Citus can perform the join locally on the worker node without pulling data over the network to the coordinator. This keeps your query latencies in the single-digit milliseconds.
If Citus is the established veteran, Multigres is the ambitious newcomer designed to change how we think about horizontally scaling PostgreSQL. Announced by Supabase and built by Sugu Sougoumarane, the co-creator of Vitess (the tool YouTube used to scale MySQL to billions of users), Multigres released its v0.1 alpha in June 2026.
Unlike Citus, which runs inside Postgres as an extension, Multigres is designed as a scalable operating system that sits in front of standard, unmodified Postgres instances. It acts as a highly sophisticated, layered proxy architecture. It solves three core problems at scale: connection pooling, high availability, and horizontal sharding.
The Multigres architecture is split into two primary software components:
One of the most exciting aspects of Multigres v0.1 is how it treats high availability (HA) as a consensus problem. Traditional Postgres replication relies on tools like Patroni or pg_auto_failover. Multigres implements a generalized consensus protocol built on top of unmodified Postgres replication. This allows it to resolve split-brain scenarios (where two database nodes both believe they are the primary) automatically without losing committed transactions.
Because Multigres uses standard, unmodified Postgres instances under the hood, you do not have to worry about extension compatibility or vendor lock-in. You can run standard Postgres 18 on your database nodes, and Multigres will handle the complex orchestration of sharding, backups, and failovers across them.
This progressive scaling journey allows developers to start with simple connection pooling on a single node and seamlessly transition to a globally sharded, high-availability cluster as their data grows to petabyte scale.
For some engineering teams, relying on third-party extensions or complex proxy systems is a non-starter. They prefer the DIY (Do-It-Yourself) route: manual, application-level sharding or using Postgres Foreign Data Wrappers (FDWs).
Manual sharding requires your application developers to build the database routing logic directly into your codebase. For instance, if you are building a global logistics application, your backend code might inspect the user's country code. If the user is in the United States, the code routes the database connection to the North American database cluster. If they are in Europe, it routes to the European cluster.
This is the exact strategy Notion used to scale their backend. They sharded their entire database across 480 individual PostgreSQL instances. While this gives you absolute control over your infrastructure, it places a massive burden on your software development team. Your developers must write custom code to handle schema migrations across hundreds of databases, orchestrate backups, and manage distributed transactions. If you need to perform a query that aggregates data across all shards (like a global financial report), your application has to fetch the data from 480 databases and join it in memory.
Alternatively, you can use the built-in postgres_fdw extension to build a sharded database at the database level. Foreign Data Wrappers allow a Postgres instance to read and write data from tables on another, remote Postgres server. You can set up a central coordinator node with parent tables, and use table partitioning to route inserts to foreign child tables hosted on separate virtual machines.
The problem with FDW-based sharding is performance. The native Postgres query planner is not optimized for distributed execution over the network. When you perform a complex query involving joins across multiple foreign tables, the coordinator node often has to pull entire datasets over the network to perform the join locally, resulting in terrible query performance and high network costs.
To help you make an informed decision for your next system architecture design, let us compare these three horizontal scaling approaches across several key technical vectors.
| Technical Vector | Citus (Extension) | Multigres (Proxy-Based OS) | Manual Sharding (DIY) |
|---|---|---|---|
| Primary Architecture | Coordinator/Worker nodes inside Postgres | Layered proxy (MultiGateway + MultiPooler) | App-level routing or Foreign Data Wrappers |
| Postgres Compatibility | 100% (runs as an extension, not a fork) | 100% (uses standard, unmodified Postgres) | Dependent on your custom app implementation |
| Sharding Mechanics | Row-level (hash) & Schema-based sharding | Progressive sharding managed by proxy layer | Custom logic or table partition routing |
| Connection Pooling | Handled via coordinator or standard poolers | Built-in MultiPooler with fair resource sharing | Manual management per shard or PgBouncer |
| High Availability | Relies on standard PG replication or cloud HA | Consensus-based HA built on PG replication | Custom failover scripts or cloud-native HA |
| Operational Maturity | High (battle-tested, enterprise-ready) | Low (v0.1 alpha as of mid-2026) | Medium to High (highly dependent on team skill) |
The right choice depends on your team's operational capabilities. If you are deploying on Kubernetes and want a modern, cloud-native, self-healing database operating system, Multigres is an incredibly exciting technology to evaluate. If you need a stable, enterprise-ready distributed database today (especially on Microsoft Azure or self-hosted servers), Citus is the clear winner. If your business logic naturally isolates data (such as geographic regions) and you have a dedicated platform team to manage the infrastructure, manual sharding might be your best bet.
To visualize the write and read scaling efficiency of these different approaches, examine the chart below. It illustrates how normalized database throughput scales as you add nodes to your cluster under a typical heavy write-and-read transactional workload.
In this chart, we normalize database throughput under high concurrent write loads. As you can see, a single primary instance (red line) flatlines immediately when hardware capacity is saturated. Manual sharding (orange line) scales but suffers from efficiency losses as cross-shard join overhead increases. Citus (green line) and Multigres (blue line) show near-linear scaling, with Multigres showing slightly superior efficiency at massive node counts thanks to its decoupled proxy architecture.
When you operate a sharded database, how your application connects to the database changes completely. In a single-node setup, your application server connects directly to the database port. In a distributed setup, sending a query to the wrong node means your database has to spend precious CPU cycles and network bandwidth forwarding that query to the correct node.
Query routing is the process of inspecting an incoming SQL statement, identifying the sharding key, and sending the query directly to the node that holds that specific shard.
In Citus, the coordinator node handles this routing. It maintains the metadata of where every shard lives. When you send a query like a select statement with a where clause matching your tenant ID, the coordinator looks up the tenant ID in its shard map, translates the query into a local query for the worker node, sends it, and returns the result.
However, this makes the coordinator a single point of failure and a potential CPU bottleneck. If your application sends 50,000 queries per second, the coordinator must parse all 50,000 queries. To solve this, Citus supports querying from any node, but this requires distributing the metadata across all worker nodes, increasing synchronization complexity.
Multigres approaches this differently. Its MultiGateway layer is decoupled from the actual Postgres instances. It parses the incoming SQL query once, regardless of how many gateways you run in your cluster. Because the gateway is stateless, you can spin up dozens of MultiGateway containers behind a standard load balancer to handle millions of incoming connections without placing any load on your actual database servers.
To understand the difference this makes in connection latency under heavy load, let us compare direct connections, standard PgBouncer, and the Multigres MultiPooler.
Under heavy concurrent connection spikes, direct connection establishment to Postgres can take up to 50 milliseconds because of the OS process-creation overhead. PgBouncer reduces this to roughly 15 milliseconds, but still introduces queueing delays when transaction pools saturate. The Multigres MultiPooler, running as a sidecar process directly on the Postgres host, lowers this latency to under 6 milliseconds by maintaining a warm, pre-allocated pool of active database connections that are shared fairly across all incoming gateways.
We believe in absolute transparency when discussing software architecture. Horizontal scaling is not a magic solution that makes every database faster. It is an engineering trade-off. You are trading simple, predictable local performance for complex, distributed scalability.
Running a horizontally scaled PostgreSQL cluster is significantly more expensive than running a single server. In our client projects, we typically see the following monthly infrastructure costs for production-grade setups:
You should completely skip horizontal scaling if your database size is under 500 gigabytes and your write volume is under 3,000 queries per second. At this scale, horizontal scaling will actually make your application slower.
Because your data is spread across different physical servers, any SQL query that needs to join tables across shards will require a distributed query plan. The coordinator has to send network requests to multiple worker nodes, wait for the responses, and merge the datasets. This introduces network round-trip latencies that can turn a sub-millisecond query into a 50-millisecond query.
If your database is struggling, first invest in maintenance and customer support to optimize your queries, add proper indexes, setup PgBouncer, and implement Redis caching. These optimizations are significantly cheaper and easier to maintain than a sharded cluster.
The single most common failure point we see in sharded database migrations is selecting the wrong sharding key. If you are building an e-commerce platform and you shard your tables by order_id instead of store_id or tenant_id, you will break query colocation.
Every time a store owner wants to view their sales dashboard, the database cannot route the query to a single node. Instead, it must broadcast the query to every single worker node in your cluster to search for orders matching that store. This is called a scatter-gather query. It completely destroys the performance benefits of horizontal scaling and can easily bring your entire database cluster to its knees.
Another common pitfall is distributed deadlocks. When two concurrent transactions attempt to update rows that reside on different shards in a different order, they can lock resources across physical servers. Detecting and resolving these deadlocks over a network is incredibly complex and frequently results in aborted transactions and application-level errors.
Key takeaways
- Exhaust Vertical Scaling First: Before sharding, implement connection pooling (PgBouncer), tune Postgres memory parameters, and utilize native table partitioning.
- Citus for Multi-Tenant SaaS: If your application has a natural sharding key (like tenant ID or company ID) and you need enterprise-ready maturity, Citus is the industry standard.
- Multigres for Cloud-Native Global Scale: If you are running on Kubernetes and want a decoupled, Vitess-inspired proxy architecture that uses unmodified standard Postgres, watch Multigres closely as it matures.
- Beware the Sharding Key: Choosing the wrong sharding key leads to devastating scatter-gather queries and high network latency. Always ensure your most frequent queries can be resolved on a single node.
- Prepare for Operational Complexity: Sharding introduces distributed transaction risks, complex backup orchestration, and significantly higher monthly infrastructure costs.
Read replicas only scale read-heavy workloads by copying data from a single primary database. All write operations must still go through the single primary node. Horizontal scaling distributes both write operations and data storage across multiple nodes, allowing you to scale write throughput and store datasets that exceed the storage limit of a single server.
Yes, Citus is fully open source and the code is available on GitHub. You can download, install, and manage Citus clusters yourself for free on your own infrastructure. Alternatively, you can use managed Citus services such as Azure Database for PostgreSQL Flexible Server Elastic Clusters.
Multigres is an open-source horizontal scaling operating system for PostgreSQL built by Supabase. It was designed by Sugu Sougoumarane, the co-creator of Vitess. It uses a proxy-based architecture to bring the same horizontal scaling and connection pooling capabilities to Postgres that Vitess brought to MySQL at YouTube.
Yes, Citus 14.0 introduced full support for PostgreSQL 18. Because Citus is built as a standard Postgres extension, upgrading to Citus 14 allows you to leverage PostgreSQL 18 performance improvements, such as asynchronous I/O and uuidv7, across your distributed cluster.
A scatter-gather query occurs when a query does not include the sharding key in its where clause. Because the database coordinator does not know which shard holds the requested data, it must broadcast the query to every worker node in the cluster, gather the results, and merge them before returning them to the client, causing high network latency.
While PgBouncer runs as a separate proxy that requires you to choose between session and transaction pooling, Multigres uses a layered architecture with MultiGateway and MultiPooler. This allows application connections to be pooled transparently and shared fairly across users without manual pool mode configuration, reducing connection latency.
You should only choose manual sharding if your application has highly isolated data silos (such as strict regional boundaries) and your engineering team has the resources to build and maintain custom query routing, schema migration scripts, and distributed backup orchestration natively in your application codebase.
The biggest risk is the dramatic increase in operational complexity. Distributed databases suffer from network latency overhead, complex query planning, risk of distributed deadlocks, and complicated backup and restore procedures. If your data model is not cleanly shardable, horizontal scaling can actually make your application slower.
Horizontally scaling PostgreSQL is no longer a luxury reserved for giant tech conglomerates. With the maturity of Citus 14 and the groundbreaking release of Multigres v0.1 alpha, engineering teams now have powerful, open-source tools to scale their relational databases to petabyte levels.
However, the key to a successful database scaling journey is knowing when to make the transition. Before you rewrite your schemas or invest in expensive proxy architectures, ensure you have optimized your single-node setup through proper indexing, query tuning, and connection pooling.
If you are planning a high-scale database migration, or if your application is beginning to hit the limits of vertical scaling, we are happy to talk it through. Our team at Algoramming has extensive experience building highly scalable architectures for global SaaS platforms, real-time logistics networks, and high-throughput transactional databases.
Whether you need to design a distributed data model, optimize your current PostgreSQL performance, or build out a cloud-native Kubernetes database cluster, we can help you navigate the transition without disrupting your users. Feel free to explore our web application design & development services or get in touch with our engineering team to discuss your database architecture.
01 · RelatedDiscover the most common PostgreSQL scalability bottlenecks and how to solve them. Learn how to optimize connection pooling, manage table bloat, configure read replicas, and partition massive databases.
Read post
02 · RelatedLocal LLM Agentic Workflows on M6 Mac Mini | Algoramming We are seeing a massive shift in how software engineering teams build and run artificial intelligence. A year ago, almost every engineering…
Read post
03 · RelatedLearn how to deploy Qwen 3.8-27B locally for private, offline AI coding agents. This guide covers hardware sizing, Ollama and SGLang setups, and sandbox security.
Read postWe will reply in plain English within one business day, NDA on request. Discovery call is free.