How Notion Handles 200+ BILLION Notes (Without Crashing)
How Notion uses horizontal scalability and sharding to handle 200+ billion notes without crashing.
Hello guys, if you are preparing for system design interview or just want to level up your Software architecture skills then there is no better way to learn than reading case studies and how others are doing.
Whenever we talk about scale we talk about Google scale or Amazon scale but today I am going to share another great story of scaling software which we use every day, Yes, I am talking about Notion, one of the fastest growing software and app.
Their story of scaling to 200 BILLION notes without crashing has many great insignts and learning about how system design fundamentals like sharding and horizontal scalability can do wonders.
Earlier I have talked about common system design concepts like Rate Limiter, Database Scaling, API Gateway vs Load Balancer and Forward proxy vs reverse proxy as well common System Design problems and concepts like Single Point Failure, and in this article we will talk about how Notion used horizontal scalability and sharding to handle 200 billion notes without crashing.
For this article, I have teamed up with Konstantin Borimechkov, a passionate Software Engineer and who has contributed some of the pieces you all have loved like his piece on ACID and transaction
With that, I hand over to him to take you through the rest of the article.
By the way, if you are preparing for System design interviews and want to learn System Design in a limited time then you can also checkout sites like Codemia.io, ByteByteGo, Design Guru, Exponent, Educative and Udemy which have many great System design courses. These will help you prepare better.
While searching for my next YouTube video to watch while studying system design, a video of how Notion scaled their system popped up
and as a Notion fan, I couldn’t just skip it.
safe to say, it was worth the watch (link at the end) and inspired me to write-up this hopefully valuable article 💪
that said, let’s start with conceptualizing sharding and then moving to the Notion’s story 👇
..
i.e. how they went from a single server to handling hundreds of billions of content blocks, while preserving excellent UX 🔥
note: no prior database wizardry required. I’ve included a glossary, going over each more complicated term used 🤘
so, what’s sharding and why does it matter?
Sharding means breaking a large dataset into many smaller partitions (shards) and spreading them across multiple machines (nodes/servers)
parallel reads/writes - each shard has its own CPU, memory, and disk, so the cluster’s total throughput grows almost linearly with node count
reduced hotspots (if done correctly) - queries touch only a slice of the table, keeping index pages hot in cache and vacuums shorter
fault isolation - if one node fails, only its shard is affected; the rest of the application stays online
operational elasticity — need more capacity? Add nodes and move shards - no “big‑bang” vertical upgrade
tl;dr: Sharding turns a single‑server ceiling into a horizontal beast for scale - at the price of extra routing logic and cross‑shard constraints
with the that out of the way let’s focus on Notion’s story. I am covering more sharding concepts in the storytelling itself 🤫
The Early Pain at Notion
2016 — a single Postgres Primary + Read Replica
that was great for beta, but terrible for growth..
but, what were the symptoms?
✔️ full‑table vacuums paused writes
✔️ index scans slowed once the blocks
table exceeded 50 M rows
✔️ large workspace imports queued millions of inserts in hours (if you’ve used Notion and imported some document or a big chunk of text, that’s spread across multiple blocks and inserted independently)
👉 the takeaway: one hot B‑tree and vacuum cycle became the pain.. quick
but why workspace_id
became the shard key ??
what even is a shard key?? that’s the field based on which you separate a single DB into many different shards. It depends on the business case, but as an example:
you have a table holding users information. you wanna shard it into multiple DBs across multiple data centers around the globe to have the user info closer geographically to each one of them.
So you pick the users.’country_of_origin’ as shard key. The result is, you have one shard (DB node) in Bulgaria with Bulgarians and another in Germany with Germans 😅
on to the question:
that’s what fit their business rules (i.e. one company having one workspace means no cross-tenant joins).
They can spread the data across shards evenly (small & large teams balancing between hash buckets)
workspaces are immutable. Users can’t merge workspaces, so the keys (workspace_id) never changes
🔑 a key point to take out from this is: stable key ⇒ router logic stays simple and re‑shards are predictable
Evolution Timeline (Numbers Approximate)
did my best in illustrating the evolution of Notion’s engineering progress throughout the years 👇
i mean, come on.. don’t I deserve a sub or like for this diagram? 😆 pretty proud of it, ngl
briefly going through each year
2018
partition tables inside one DB by
workspace_id
what was the impact? Vacuums run per‑partition now; p95 WRITE latency down 40 %
2020
this year Notion ran 32 physical Postgres servers, each one carrying 15 logical shards, for a total of 480 logical shards across the fleet
what was the impact? multi-year head-room; lower p-latencies & faster pages; balanced resource util; fault isolation..
2022
the Great Re‑Shard happen (i.e. live split of hottest partitions) more in this YouTube vid:
what was the impact? CPU & I/O head-room restored;
2023
Notion offloads the Big Analytics query to a separate data lake, developed using open-source software (Apache Hudi on S3)
what was the impact? the heavy analytical queries didn’t bother the business/transaction ones
2024
hitting 200 Billion Blocks & implementing in-house weekly auto‑rebalance
what was the impact? shard skew < 1.4× - keeps query plans stable
Lessons You Can Apply at 1/1000‑th Scale
be brave when picking a shard key - changing it later hurts
separate analytics sooner; cold queries age the primary. Better for analytics as data folks can use more tools, better for the business logic and servers as they don’t get locked by big analytics queries
implement robust monitoring of shards & more specifically - shard skew. Add alerts when max/min size > 2X
abstract connections behind a router library; apps call
getConn(id)
automate re‑sharding (cron + pg_dump beats manual midnight ops)
A lil glossary in case you don’t know some used terms 🤝
shard skew - the ratio between the busiest shard (by disk or QPS) and the quietest
router - tiny service/library that looks at a key and points to the right database
hot shard - one slice is busier than the rest, causing CPU/disk spikes
re-shard - split or move data to make shards even again, live and online
consistent hash - hashing trick so adding a new DB moves only a few keys, not everything
Real‑World Sharding Examples Beyond Notion
Shopify Stores - each merchant is a shard in MySQL. A re‑shard tool “Kiseki” live‑moves busy stores
Stripe Ledger -
customer_id
shard key across Postgres ranges for strict balance consistency
they use mostly the same playbook, just on different scale and based on different business needs & spec!
Hope you found this valuable! The video and going deeper with the blog-article really helped me to master the theory behind sharding!
Let’s crush it this week!
oh.. here’s the link to the YouTube vid as promised at the start as well 🤘
Drop a ❤️ to help me spread the knowledge & to let me know you’d like more of this!
Enjoyed this? Consider subscribing to The Excited Engineer for weekly deep dives just like this 👇
Other System Design and AI articles you may like
What tool did you use for diagrams??
That was an interesting one to do research on and write! Thanks for sharing through the Java Revisited newsletter javinpaul 💪🔥