Federation
Federation (also called functional partitioning or vertical partitioning by function) splits a database by domain — users in one database, posts in another, messages in a third — so each can scale, fail, and evolve independently. Unlike sharding (which splits one table's rows across machines), federation splits by function: every database holds a different slice of the schema, and the application stitches them together.
Foundational.
How it works
Federation splits a single logical database into multiple physical databases along functional boundaries. Where sharding divides one table's rows across machines, federation divides the schema: a users database, a posts database, a messages database, a billing database. Each is independently scaled, deployed, backed up, and operated.
The motivation isn't usually raw throughput — it's organizational and operational. A single shared database means:
- One team's schema migration blocks everyone's deploy.
- A hot row in
messagessaturates the entire instance, slowing downlogin. - A catastrophic bug in one service corrupts data for everyone.
- Engineering teams queue on a single DBA team to provision capacity.
Federation solves this by giving each functional slice its own database (and, in mature versions, its own service that owns it). The cost is that cross-domain queries — once a JOIN — now require either application-level stitching, denormalized copies, or asynchronous event-based synchronization.
This pattern is sometimes called 'vertical partitioning' in older texts, but that term is overloaded — in SQL circles it can also mean splitting a table's columns across tables on the same machine. 'Federation' is the unambiguous term for splitting by function across machines.
Choosing federation boundaries is the same art as choosing microservice boundaries: align with bounded contexts (domain-driven design) and team ownership. A few rules of thumb:
- Split by entity that's read/written together — if every 'create post' writes only to posts and tags, those can share a database; if it also writes to a user's
post_count, consider whether that count belongs in the posts DB instead. - Split by access pattern — billing (transactional, ACID) and analytics (read-heavy, columnar) want different databases anyway.
- Split by team — Conway's Law says your database shape will mirror your org chart. Embrace it: one team owns one database, end to end.
- Split by scale curve — if messages grow 10× faster than users, separating them lets messages get their own capacity planning.
- Don't split by foreign key — that's a sign you need the data together, not apart.
Once split, the application code is responsible for assembling cross-domain views. A user's profile page that shows their posts, message count, and recent purchases must query three services and merge results in memory — or rely on denormalized projections updated by events.
In a federated system, the query SELECT u.name, COUNT(p.id) FROM users u JOIN posts p ON u.id = p.user_id GROUP BY u.name is no longer a single SQL statement. It's two queries: fetch users from the Users DB, fetch post counts from the Posts DB, then merge in application code (or rely on a precomputed view). The architectural pattern for the latter is CQRS + materialized views: the Posts service emits 'post created' events, the Users service consumes them and updates a denormalized post_count field. Now the profile read is back to one query — but at the cost of eventual consistency and event infrastructure.
Federation and sharding are orthogonal and often combined:
- Federation splits by function: users DB, posts DB, messages DB. Each slice owns different tables.
- Sharding splits by row within one table: users 1-1M on shard A, 1M-2M on shard B.
- Both: a federated posts DB that's also sharded by
user_idfor write scaling.
The progression most teams follow:
- Single database — start here. Simplest. Fine until ~10k QPS or team coordination pain.
- Read replicas — scale reads without changing the data model. Writes still bottlenecked.
- Cache layer (Redis/Memcached) — absorb read traffic for hot data. Writes still bottlenecked.
- Federation — split by function. Solves the coordination problem, lets each piece scale independently. Cross-domain queries now require stitching.
- Sharding within a federated slice — when one slice's write throughput exceeds a single machine.
A common mistake is jumping to sharding before federation. Federation is usually cheaper, simpler, and addresses the operational pain first. Sharding is complex (rebalancing, cross-shard queries) and should be reserved for when even a federated slice outgrows one machine.
The microservices principle of 'each service owns its data' is federation applied to architecture. A well-designed microservices system has no shared database: each service has its own, optimized for its workload (SQL for billing, Cassandra for messages, Redis for sessions). Cross-service data access happens via APIs, never direct DB queries. Skip this rule and you have a 'distributed monolith' — services that look independent but share state and can't be deployed independently.
Federation shifts you from ACID transactions within one database to eventual consistency across databases. A user registration flow that used to be INSERT user; INSERT welcome_message; INSERT default_preferences; COMMIT is now three writes to three databases — and there's no atomic commit.
Patterns for handling this:
- Saga pattern — orchestrate multi-database writes as a sequence with compensating actions on failure. The de-facto replacement for 2PC in microservices.
- Outbox pattern — write the data and the 'event to publish' in the same database transaction; a separate process reads the outbox table and publishes events. Guarantees the event is emitted if and only if the data is committed.
- Idempotent retries — every operation must be safely retriable; partial failures must not corrupt state.
- Acceptable inconsistency — for non-critical data (analytics counters, search index updates), eventual consistency is fine.
Two-phase commit (2PC) across federated databases is technically possible but slow, fragile, and almost universally avoided in modern systems. Sagas are the modern answer.
Your monolithic PostgreSQL database is hitting capacity: messages are growing 10× faster than users, the messages team's migrations keep blocking deploys for everyone, and a hot row in messages occasionally saturates the instance. What's the right first step?
Pick one answer.
After federating, a profile page that needs the user's name (Users DB), their last 5 posts (Posts DB), and unread message count (Messages DB) — what's the standard approach?
Pick one answer.
What's the relationship between federation and sharding?
Pick one answer.
Engineering mental model
Mental model. Think of Federation as a deliberate boundary in a system. The boundary exists because something becomes harder to manage when everything is done in one place: latency, scale, failure isolation, consistency, cost, or team ownership. The useful question is not “what does Federation mean?” but “what pressure makes this boundary worth introducing, and what new failure mode does it create?”
Before choosing Federation, name the workload, the critical user path, the dominant bottleneck, the failure you are trying to absorb, and the trade-off you are willing to accept. If you cannot name those five things, the design is probably premature.
// Pseudocode
request = receive()
result = federation(request)
return result
// Production questions:
// 1. What happens on timeout?
// 2. Can this operation be retried safely?
// 3. What is the bottleneck?Back-of-the-envelope reasoning
Numerical lens: write down traffic, payload size, read/write ratio, peak multiplier and durability target before choosing a component. The numbers should justify the architecture.
Interactive thought experiment: Federation
Change the variables below and predict what breaks first in Federation. The production lab can later reuse these same inputs.
Change one variable at a time. Predict the failure mode first, then move the slider and see whether your mental model matches the simplified system response.
If you are stuck on Federation, start by drawing the request path and marking every network hop, stateful component, queue, cache and failure boundary. Then estimate where the system will saturate.
You increase traffic by 10× in a system using Federation. What should you inspect first?
Pick one answer.
Which statement is the safest engineering habit when using Federation?
Pick one answer.
You have dashboards for traffic, latency, errors and saturation. You can change the architecture, but every change has operational cost.
Production scenario: your system uses Federation, traffic suddenly spikes, and p99 latency doubles. What is your first move?
Interview drill
Answer this without notes: When would you choose Federation, and when would you intentionally avoid it? Mention at least one bottleneck it addresses, one failure mode it introduces, and one alternative. Then quantify the workload you are designing for.
For Federation, start with access patterns rather than brand names. Identify the dominant reads/writes, data relationships, consistency requirements, partition key, hot keys and failure behavior before choosing a storage strategy.
Numerical sanity check
A rough capacity check: required write throughput ≈ peak writes/s × average record size. At 5,000 writes/s and 2 KB average payloads, the raw incoming data stream is about 10 MB/s before indexes, replication and overhead.
Do not optimize for a memorized definition. Reason from the workload and failure mode.
A team proposes Federation because it 'scales'. What workload characteristic would make that choice a poor fit?
Pick one answer.
What you gain, what you pay
- +Independent scaling — each functional slice grows on its own curve.
- +Independent failures — a messages DB outage doesn't take down login.
- +Independent deploys — schema migrations are scoped to one team.
- +Technology fit — each slice can use the best tool (PostgreSQL for billing, Cassandra for messages, Redis for sessions).
- +Team autonomy — Conway's Law made explicit; teams own their data end-to-end.
- +Blast-radius reduction — a bad migration corrupts one slice, not everything.
- −Cross-domain queries are no longer JOINs — they require application-level stitching or denormalized views.
- −No atomic transactions across databases — sagas or eventual consistency required.
- −Operational overhead — N databases to back up, monitor, secure, and upgrade.
- −Distributed-system complexity — partial failures, retries, idempotency.
- −Data duplication — denormalized copies of 'shared' data (user name, etc.) live in multiple slices.
- −Harder to migrate to later — once federated, unifying back is painful.
How this breaks in production
- Distributed monolith — services with separate DBs but tightly coupled schemas and synchronous calls; deploys still can't be independent.
- Shared database anti-pattern — services nominally separated but all reading/writing one database; no real isolation.
- Cross-database transactions via 2PC — slow, fragile, blocking; usually replaced by sagas after the first incident.
- Denormalization drift — copies of shared data (user name) become stale when source updates and consumers don't get the event.
- Hot slice — one function dominates traffic and saturates its database, requiring follow-on sharding.
- Schema duplication — the same `User` concept defined differently in each slice's database.
Don't fall into these traps
- •Sharding before federating — paying sharding complexity when federation would have addressed the pain.
- •Allowing services to read each other's databases directly — undermines isolation and creates coupling.
- •Treating cross-domain queries as atomic — assuming reads across slices are consistent.
- •Not investing in event infrastructure (Kafka, etc.) before federation — limits your options for keeping data in sync.
- •Forgetting operational tooling — N databases need N backups, N monitors, N runbooks.
- •Splitting by foreign key instead of bounded context — fragments entities that should stay together.
Real systems using this
How real systems implement this
- Shopify — Federates its database by function (shops, orders, checkouts, billing) and shards each federated slice by shop_id. Their engineering blog is a textbook case study of the federation → sharding progression.
- Twitter / X — Federated early into separate databases for users, tweets, social graph, and timelines. Each scales independently and uses different storage tech tuned to its workload.
- Uber — Originally a monolith; migrated to a federated, database-per-service architecture. Each service owns its data — Schemaless (custom MySQL-based) for most, Cassandra for trip data, Redis for caching. Schema migrations are now per-service.
- Netflix — Each microservice owns its own database — Cassandra for viewing history, EVCache for hot reads, MySQL for billing. Cross-service data access is via API calls, never direct DB queries.
Practice saying it out loud
- Q1What's the difference between federation and sharding? When would you choose each?
- Q2Your team is hitting the limits of a monolithic PostgreSQL database. Walk through the progression of scaling steps you'd take.
- Q3After federating, how do you handle a request that needs data from three different databases?
- Q4How do you maintain consistency across federated databases without two-phase commit?
- Q5What's the 'database per service' microservices principle, and why does it matter?
Further reading & references
Core explanations are original NO CAP material. External references are provided for deeper study and standards.
What next?
Mark as understood once the mental model clicks.
Next recommended
Sharding