Vibe Engines
YouTube
System Design

Design Pastebin

Step 1 / 9

Learn system design by building a text-paste service like Pastebin step by step.

The numbers to beatbase62encoding~7charstrillionsof keys

The whole design, in writing

Learn system design by building a text-paste service like Pastebin step by step. An interactive guide covering unique key generation, separating metadata from blob storage, caching and CDN for read-heavy traffic, TTL expiration, privacy, and async analytics.

Every step of the build above, written out: the problem each piece solves, the option that was taken and the ones that were not, the numbers, and how it fails in production.

The big idea

What is Pastebin?

Paste some text, get a short link, share it; anyone who opens the link sees the text. Dead simple — but at scale it’s a sharp lesson in read-heavy design: pastes are written once and read thousands of times, sometimes from all over the world.

CreatorPOST a pasteReaderGET /aZ9k2
New in this step: Creator, Reader.

Mint a unique short key, store the (potentially large) text in a blob store with only a pointer in the database, and make the read path fly with caching and a CDN. It’s the URL shortener’s cousin — but with real content to store and expire.

What the new pieces do

Creatorclient
Pastes some text — a log, a snippet, an error — and gets back a short URL to share. Writes are rare compared to reads.
Readerclient
Opens a shared paste link. Expects the text to load instantly, possibly thousands of times for one popular paste.

Step 1 · The skeleton

Store text, return a key

Two operations: create (take text, give back a key) and read (take a key, give back text). A paste can be a few bytes or a few megabytes, so where the text lives matters from the start.

API ServerMetadata DBObject Store
New in this step: API Server, Metadata DB, Object Store. · swipe to pan the diagram

A paste can be a few bytes or a few megabytes. Where do you put the text?

  1. Multi-megabyte bodies bloat the DB, slow every query, and waste its indexed storage on data you only fetch by key. Keep big bodies out of the database.

  2. The DB holds tiny queryable rows (key → location, TTL, flags) while the object store holds the bulk. Same split as photos/videos — small fast database, bulk where bulk belongs.

  3. In-memory pastes vanish on restart and can’t scale past one machine’s RAM. Pastes must be durably stored, with memory used only as a cache later.

The API Server writes the text to an Object Store and a small row to the Metadata DB mapping the key to that text’s location. Reads resolve the key in the DB, then fetch the body from the blob store.

Why this piece earns its place

Two stores means two writes and no transaction spanning them, so the order is part of the design. Write the body to the object store first, then the metadata row. If the process dies in between, you are left with an orphan body nobody can reach — invisible to readers, costing only storage, and reclaimable later by the same background sweep that handles expiry. Do it the other way and a crash leaves a row whose pointer resolves to nothing: a live key that hands readers a 500 instead of a paste. Deletion runs in the mirror image — drop the row first so the key stops resolving, then remove the body — because the window you can tolerate is “the bytes exist but nothing points at them”, never “the key still works but the bytes are gone”. The same asymmetry decides what a read does when a pointer misses: treat it as gone, alarm on it, and never retry into the store hoping the body turns up.

What the new pieces do

API Serverbackend
Handles both operations: store a new paste and return its key, or look up a key and return the text. The single front door.
Metadata DBstore
Small rows: the key, where the text lives, expiry time, and privacy flag. Queried on every read to resolve a key to its blob.
Object Storestore
The actual paste bodies. Kept out of the database so large pastes don’t bloat it; the DB holds only a pointer here.

Step 2 · The short link

Mint a unique key

Every paste needs a unique, short, URL-safe code like /aZ9k2. Hashing the content collides on identical pastes and yields long codes; pure random forces a “taken?” check on every write.

API Servercreate + fetchKey Genunique short id
New in this step: Key Gen.

Every paste needs a unique short URL-safe code like /aZ9k2. How do you mint it without collisions?

  1. Hashing collides on identical pastes (two people paste the same snippet → same key, overwriting), and full hashes are long. You need short codes unique regardless of content.

  2. Random codes force a "is it taken?" lookup on every create, and collisions rise as you fill the space. Uniqueness by construction avoids the check entirely.

  3. Counting up then base62-encoding guarantees no collisions without any lookup; ~7 chars covers trillions of pastes. (Or hand out pre-generated unused keys.) Unique by construction.

Use a Key Gen Service: take a counter and encode it in base62, or hand out pre-generated unused keys. Codes are unique by construction, so creating a paste never needs a collision check.

Why this piece earns its place

A counter is one number, and every create in the system queues behind it — you have traded a collision check for a single point of contention, and if that counter is one row somewhere, a single point of failure too. The fix is to stop dealing keys one at a time: each Key Gen instance claims a block of the range in one atomic increment and then hands ids out of memory, so the shared counter is touched once per block instead of once per paste. Block size is the knob. Big blocks mean almost no coordination, at the cost of a bigger hole in the keyspace every time an instance dies with a block half spent — and holes are exactly what a space of 3.5 trillion keys can afford to lose. Small blocks waste fewer codes and put you back on the shared row under load. I’d rather burn keys than serialize creates. The one property a block allocator can never lose is that no block is ever handed out twice, so that increment has to be genuinely atomic, not read-then-write.

  • base62encoding
  • ~7chars
  • trillionsof keys

What the new pieces do

Key Genservice
Mints a unique short code (base62) for each paste so two pastes never collide — uniqueness by construction, no “is it taken?” check.

Back of the envelope

base62, ~7 chars
62^7 ≈ 3.5 trillion keys
counter ⇒ unique by construction
no collision check on create
short + URL-safe
a–z A–Z 0–9, no escaping

Step 3 · Reads dwarf writes

Cache hot pastes

A paste shared in a popular thread gets read thousands of times. Hitting the metadata DB and blob store for every one of those identical reads is wasteful and slow.

API ServerCacheObject Store
New in this step: Cache. · swipe to pan the diagram

A paste in a popular thread is read thousands of times. How do you avoid hitting the DB + blob store every time?

  1. Replicas add throughput but every hot read still does a full store fetch for identical, unchanging content. When the same paste repeats, serve it from memory instead of re-fetching.

  2. A hit returns the text in <1ms; a miss falls through to the blob store and warms the cache. Pastes are write-once, so there’s no invalidation — caching is pure upside from the second read on.

  3. You can’t control reader behavior, and the goal is to serve many readers fast. The system must make repeat reads cheap server-side via caching, not push work onto users.

Put a Cache (Redis) on the read path keyed by paste id. A hit returns the text in under a millisecond; a miss falls through to the blob store and warms the cache. Because a paste’s text never changes, it’s perfectly cacheable.

Why this piece earns its place

The cache is a fixed memory budget and paste bodies do not share a size, which is the trap here. A handful of multi-megabyte pastes admitted by value will evict thousands of small hot ones, and that eviction is silent: hit-rate sags, latency climbs, nothing errors. So cap what is cacheable as content — small bodies go in whole, and anything above the cap caches only its metadata row, so the read still skips the DB and streams the body from the object store. That keeps most of the win, because the expensive part of a large paste is moving the bytes, not finding them. The other thing worth a cache entry is the negative answer. Keys are never reused, so a key that resolves to nothing today resolves to nothing tomorrow, and a link shared widely keeps getting clicked long after the paste is gone. Hold those misses briefly too, or every dead link in an old thread is a database lookup you pay for forever.

  • <1mscache hit
  • 100:1reads : writes
  • noinvalidation

What the new pieces do

Cachecache
Redis holding the most-read pastes. A popular link is served from memory in under a millisecond instead of fetching the blob every time.

Back of the envelope

~100:1 reads : writes
write once, read thousands of times
hit ≈ <1ms RAM
vs a DB lookup + blob fetch
immutable ⇒ no invalidation
caching is pure upside

Step 4 · Readers everywhere

Go global with a CDN

Your cache and store sit in one region, but readers are worldwide. A paste opened from another continent pays a long round-trip on every fetch.

ReaderAPI ServerCacheCDNObject Store
New in this step: CDN. · swipe to pan the diagram

Your cache and store sit in one region but readers are worldwide. How do you cut the cross-continent round-trip?

  1. More nodes in one region don’t help a reader on another continent — they still pay the long round-trip on every fetch. You need content closer to the reader, geographically.

  2. Hand-rolling global replication of all content is expensive and heavy when most pastes are never read in most regions. A CDN already does edge caching on demand.

  3. The first reader in a region pulls through the edge; everyone after is served locally. Immutable pastes cache at the edge with long TTLs — the cheapest scaling for read-heavy payloads.

Front the read path with a CDN. The first reader in a region pulls the paste through the edge; everyone after is served locally. Immutable content plus a long TTL means the edge does the heavy lifting.

Why this piece earns its place

The long TTL rests on an assumption worth naming: a paste is immutable, so a copy of it can never go wrong. That holds until a paste has to stop existing — an expiry passes, an author changes its visibility, someone reports content that has to come down. From this step on, the origin is no longer the only place the bytes live, and an edge copy has its own lifetime that nothing in the metadata DB governs. Two defenses, and you want both. Bound the edge TTL by the paste’s remaining life so a cached copy can never outlive the paste it came from — free for pastes with no expiry, and it makes short-lived ones cheap to reason about. And purge explicitly on delete instead of waiting a TTL out. Then be honest about what a purge is: a request that propagates across an edge fleet, not a transaction. The real guarantee is “gone at the origin now, gone at the edge shortly”, so anything that must be unreachable the instant you say so should never have been edge-cacheable at all.

What the new pieces do

CDNcache
Caches paste content near readers worldwide. Since a paste’s text is immutable, it can sit at the edge with a long TTL.

Back of the envelope

1st regional read pulls through edge
every reader after is served locally
immutable + long TTL
the edge does the heavy lifting
offloads latency + bandwidth
origin barely touched

Step 5 · Don’t keep it forever

Expiration & TTL

Many pastes are meant to be temporary (“expire in 1 hour / 1 day”), and keeping every paste forever steadily fills storage with dead content nobody will ever read again.

API ServerKey GenCacheCDNMetadata DBObject StoreExpiry Worker
New in this step: Expiry Worker. · swipe to pan the diagram

Many pastes are meant to be temporary ("expire in 1 hour"). How do you stop storage filling with dead content?

  1. An expiry on the record makes cleanup routine: expired keys return 404/410, lazy deletion drops them on access, and a background worker (or native store TTL) sweeps the rest. Lifetime becomes data.

  2. Manual cleanup doesn’t scale and risks deleting the wrong thing under pressure. Expiry should be declared per paste and enforced automatically, not firefought.

  3. Keeping every temporary paste forever fills storage with content nobody will read again, and ignores users who explicitly wanted expiry. TTL is both a feature and a cost control.

Store an optional TTL with each paste. An Expiry Worker (or the store’s native TTL) removes expired pastes from the blob store and metadata, after which the key returns a clean 404/410.

Why this piece earns its place

Be clear about which half of this carries the guarantee, because it changes how hard the other half has to work. The check on read is what makes an expired paste unservable: it sits in the request path, it reads the expiry off the row it already fetched, and it cannot lag. The worker is only reclaiming space, which means it is allowed to be late — and treating it as a batch job rather than a deadline is what keeps it affordable. That matters because the naive version scans every paste hunting for dead ones, turning a chore into a full pass over a table that only grows. Index by expiry time, or bucket keys into the hour they die in, so the worker reads only what is actually due. Then rate-limit it, because expiry is bursty by nature: a spike of one-hour pastes created together comes due together, and a worker deleting as fast as it can will aim that burst at the same store serving reads, converting a storage chore into a latency incident.

What the new pieces do

Expiry Workerworker
Removes pastes whose TTL has passed from the store and metadata, reclaiming space so expired links return 404.

Step 6 · Who can see it?

Privacy & limits

Not every paste should be public. Some are unlisted (only those with the link) or private (only the author). And without size limits, one user can paste a gigabyte and wreck your storage and bandwidth.

CreatorReaderAPI ServerKey GenCacheCDNMetadata DBObject StoreExpiry Worker
The system as it stands at this step. · swipe to pan the diagram

Some pastes should be unlisted (link-only) or private (author-only). How do you enforce that?

  1. An obscure URL is "security by obscurity" — unlisted is not private. Links leak, get shared and indexed, so true privacy needs a real access check, not just a random key.

  2. Hiding from a listing does nothing if anyone with the key can still GET the content. The read path itself must verify permission, not just the discovery surface.

  3. Store a per-paste flag; public serves freely, unlisted needs the key, private requires the author’s auth — checked on every read. Pair with size caps and rate limits so abuse can’t balloon costs.

Add a privacy flag per paste, enforced at the API on every read, and require the right key/auth for private ones. Cap paste size and rate-limit creation so abuse can’t balloon costs or hammer the service.

Why this piece earns its place

Privacy changes something upstream of the check itself: after the last two steps the read path has several entrances, and only one of them can enforce anything. A request answered at the edge never reaches the API server, so a private paste that is edge-cacheable is a paste whose permission check has been designed out — and a shared cache can hand a body fetched for one authorized reader to the next person who asks. So the flag has to decide cacheability before it decides access. Public and unlisted bodies can be cached anywhere, since their only protection was ever the key. Private bodies are marked uncacheable end to end, skip the shared tiers, and are read from the store after the author is authenticated. You are knowingly giving up the sub-millisecond path for that class of paste, which is the right trade: private pastes are rare and read by one person. The size cap belongs at the same boundary — enforce it while the upload streams, not after you have already accepted and stored the bytes.

Step 7 · Counts & scale

Analytics, async

Owners want view counts, but writing an analytics row on every read would slow the one thing that must stay fast — and billions of small rows pile up in one database over time.

API ServerCacheCDNObject StoreExpiry WorkerAnalytics
New in this step: Analytics. · swipe to pan the diagram

Record views asynchronously (fire an event, aggregate later) so reads never block on counting. Shard the Metadata DB by key and lean on the cache/CDN so the read path stays flat as paste count grows into the billions.

Why this piece earns its place

The count has a measurement problem created by this design’s own success. The CDN exists precisely to stop reads reaching the origin at all, and it works — most views of a popular paste are answered at the edge, and the API server never sees them. A Redis hit is not the same thing: it is served by the API server, so it is precisely the read the origin does see and can count. But a counter incremented only where the request happens to land undercounts exactly the pastes that are read most, and it gets worse every time the edge does its job better. The owner ends up watching a number that tracks edge caching rather than readership. Count where the reads actually are: treat the CDN’s access logs as the primary source, aggregate them on a schedule, and use the origin’s own events only for the traffic the edge never sees. That also explains why this number is best-effort by construction — logs arrive in batches, late, and sometimes not at all — so present it as a view count and never let anything that has to be exact, like billing or a rate limit, depend on it.

What the new pieces do

Analyticsstore
Tracks how often each paste is viewed, updated asynchronously so counting a view never slows the read itself.

You did it

You just designed Pastebin.

CreatorReaderAPI ServerKey GenCacheCDNMetadata DBObject StoreExpiry WorkerAnalytics
The finished design, end to end. · swipe to pan the diagram

Everything you assembled, in order

  • Create/read over an API, with text in a blob store and a pointer in the DB.
  • Base62 keys from a Key Gen Service — unique by construction.
  • A Redis cache makes the read-heavy, immutable path sub-millisecond.
  • A CDN serves pastes from the edge for global readers.
  • TTL-based expiry (lazy delete + sweep) keeps storage from filling with dead pastes.
  • Per-paste privacy flags, size caps and rate limits for the real world.
  • Async analytics and a sharded metadata DB keep the read path flat at scale.

Where an interviewer pokes next

Getting the boxes right is the easy half. These are the questions that separate a candidate who drew the diagram from one who has run the thing. Answer each one out loud before you open it.

  1. How is Pastebin different from a URL shortener?

    Same key-generation idea (base62, unique by construction) and the same read-heavy caching, but Pastebin stores real content. That adds a blob/object store separate from metadata, size limits, expiration/TTL, and privacy — whereas a shortener only stores a tiny target URL. Pastebin is "shortener + content lifecycle."

  2. Why separate metadata from the blob instead of one row?

    Bodies range from bytes to megabytes; inline they bloat the database, slow scans, and waste its indexed storage on data you only fetch by exact key. Splitting keeps the DB small and fast for lookups it’s good at (key → location, TTL, flags) and puts bulk in cheap object storage built for it.

  3. A paste goes viral — how do you handle the hot read?

    It’s the easy case because pastes are immutable: the CDN edge and Redis cache absorb essentially all of it after the first fetch, with no invalidation to worry about. If a single key strains one cache node, replicate that key across nodes or lean on the CDN’s fan-out — the hot-key playbook, made trivial by immutability.

  4. How do you prevent abuse (spam, illegal content, giant pastes)?

    Layered guardrails: a max paste size, per-IP/account rate limits on creation, and content scanning / abuse reporting with takedown. Private and unlisted flags limit exposure but don’t replace moderation. These boring controls keep a free, public, write-accepting service from being weaponized or bankrupted.

  5. How do you expire pastes precisely at scale?

    Two layers: lazy deletion (on read, if past TTL return 410 and delete) handles anything anyone accesses, and a background sweep (or the store’s native TTL index) reclaims the rest no one reads. You don’t need millisecond precision — "gone shortly after expiry, never served once expired" is the guarantee, which lazy + sweep gives cheaply.

Check yourself — the answers, and why

Eight steps in, these are the calls you should be able to make cold. Pick one, then read why.

  1. Paste text lives in a blob store (not the DB) because…

    Split metadata from content — small fast DB rows, bulk in object storage.

  2. Base62 keys from a counter are unique…

    Counting up then base62-encoding never collides; ~7 chars covers trillions.

  3. Caching pastes is pure upside because pastes are…

    No edits means no cache invalidation; the second read onward is essentially free.

  4. A CDN helps most because the workload is…

    Edge-caching immutable content with long TTLs moves latency and bandwidth off the origin.

  5. "Unlisted" pastes are…

    An obscure URL isn’t security; private pastes require real auth enforced at the API.

How you’d open this design in an interview

Before any boxes: agree what it must do, pin the qualities that shape everything, then build — naming each trade-off as you make it. The walkthrough above is that exact order.

What it must do

Agree on these before drawing a single box.

  • Create: take text, store it, and return a short URL-safe key.
  • Read: GET /aZ9k2 resolves the key and returns the paste text — the hot path.
  • Expire: optional TTL — pastes can die on schedule and return a clean 404/410.
  • Privacy: public, unlisted (link-only), or private (author-only), enforced on every read.
  • View counts: owners see how often a paste is read, counted without slowing the read.

The qualities that shape everything

Each one names the mechanism that buys it.

The database stays small and fast
A metadata/content split — paste bodies live in an object store, the DB holds only a tiny key → location, TTL, flags row.
No two pastes ever collide
A counter encoded in base62 by a Key Gen Service — unique by construction, no "is it taken?" check on create.
Sub-millisecond reads for hot pastes
A Redis cache keyed by paste id in front of the store; a miss falls through and re-warms, and immutable text means no invalidation.
Fast reads for a global audience
A CDN edge-caches immutable paste content near readers with a long TTL, moving latency and bandwidth off the origin.
Storage doesn’t fill with dead pastes
A per-paste TTL with an Expiry Worker (or the store’s native TTL) — lazy delete on read plus a background sweep.
Analytics never slows a read
Views are recorded asynchronously (fire an event, aggregate later) and the metadata DB is sharded by key.

The trade-offs you say out loud

Senior signal isn’t the boxes — it’s naming what you gave up and why it was the right price.

Text in a blob, pointer in the DB over the paste body inline in the database

Multi-megabyte bodies bloat the DB, slow every query, and waste indexed storage on data only fetched by key. A tiny row plus cheap object storage keeps the database small and fast.

Counter + base62 (KGS) over hashing the paste content

Hashing collides on identical pastes (two people paste the same snippet → same key) and yields long codes. A dealt-out counter is unique by construction — no collision check on the write path.

Cache-aside Redis over read replicas of the blob store

Replicas add throughput but every hot read still does a full store fetch for identical content. A cache serves the second read onward from memory in <1ms, and immutable pastes need no invalidation.

A CDN at the edge over replicating the store to every region yourself

Hand-rolled global replication is expensive and wasteful when most pastes are never read in most regions. A CDN edge-caches immutable content on demand — the cheapest scaling for read-heavy payloads.

An access check on every read over relying on a hard-to-guess URL

An obscure URL is security by obscurity — unlisted is not private. Links leak, get shared and indexed, so private pastes need a real permission check on the read path, not just a random key.

The answer, out loud

What a strong answer to “Design Pastebin” sounds like, first question to last trade-off. It is about 7 minutes of talking; the whiteboard and the interviewer fill the rest of the 45. Read it aloud once, then close the page and give it yourself.

  1. 0–3 min

    Scope it before drawing

    Let me scope this before I draw anything. Someone pastes text, gets a short link, and anyone with that link reads it back. What decides the whole design is the shape of the traffic: a paste is written once and read a lot — I’d work from roughly a hundred reads per write, and one popular link can carry thousands on its own. So it’s read-heavy, and the content never changes after it’s created. I’d also ask up front whether pastes can expire and whether they can be private, because both of those land on the read path rather than the write path.

  2. 3–9 min

    Where the text lives

    Two operations: create takes text and returns a key, read takes a key and returns text. The first real decision is where the text goes, because a paste can be a few bytes or a few megabytes. I’d keep it out of the database. The database holds a small row — the key, where the body lives, when it expires, who may see it — and the body goes in an object store. That keeps the database small enough to answer key lookups fast, and I’m not paying indexed storage for data I only ever fetch by exact key.

    Built in step 1: Store text, return a key
  3. 9–15 min

    Minting the key

    Then the key itself. I wouldn’t hash the content: two people pasting the same snippet land on the same key and overwrite each other, and hashes are long. I wouldn’t use pure random either, because then every create has to ask whether that code is already taken. I’d take a counter and encode it in base62 — letters and digits, all URL-safe. Around seven characters gets me on the order of three and a half trillion keys, and they’re unique by construction, so creating a paste never does a collision check. I’d put that behind its own key generation service.

    Built in step 2: Mint a unique key
  4. 15–21 min

    The read path

    Now the reads, which is where the interesting work is. A link in a busy thread is the same bytes fetched over and over, and going to the database and then the object store for each one is waste. So I’d put a cache in front keyed by paste id: a hit comes back in under a millisecond, a miss falls through and warms it. What makes this unusually easy is immutability. There’s no edit, so there’s no invalidation, and I never have to reason about a reader seeing an old version.

    Built in step 3: Cache hot pastes
  5. 21–27 min

    Readers are not in my region

    That cache still sits in one region and readers don’t. I’d rather not replicate the store everywhere myself — most pastes are never read in most regions, so I’d be paying to move content nobody asks for. A CDN does it on demand: the first reader in a region pulls the paste through the edge, everyone after is served locally, and because the content is immutable it can sit there with a long time to live. For a read-heavy service that’s the cheapest scaling I can buy, and it takes bandwidth off the origin as well as latency.

    Built in step 4: Go global with a CDN
  6. 27–33 min

    Pastes that are meant to die

    Plenty of pastes are temporary — an hour, a day — and keeping everything forever fills storage with content nobody will open again. So the lifetime is part of the record: an optional TTL stored with the paste. Once it passes, the key returns a clean 404 or 410 instead of the text, and the paste goes away — lazily when someone touches it, and by a background worker or the store’s own expiry for the ones nobody touches. That makes cleanup routine maintenance rather than something I do in a panic.

    Built in step 5: Expiration & TTL
  7. 33–39 min

    The unhappy path

    Not every paste should be public, so the record carries a visibility flag: public, unlisted, or private. The thing I’d say out loud is that unlisted isn’t private — a hard-to-guess link is still a link, and links get forwarded, shared and indexed. Private means a real permission check against the author on every read. Alongside it I’d cap paste size and rate-limit creation per account and per address, because this endpoint accepts arbitrary content from anyone, and without those two limits one user can spend my storage and bandwidth at will.

    Built in step 6: Privacy & limits
  8. 39–43 min

    Counting, and growing

    Owners want view counts, and I’d keep that off the request deliberately. The read is the one thing that must stay fast, so a view fires an event and gets aggregated later; if the number lags a little, nobody is hurt. On storage, as the paste count grows I’d shard the metadata by key — every lookup is by exact key, so there’s no cross-shard query to worry about, and the cache and the edge keep most reads from reaching a shard at all.

    Built in step 7: Analytics, async
  9. 43–45 min

    Close on the trade-off

    So: a small row plus a body in object storage, counter-based base62 keys, a cache and a CDN carrying the reads, lifetime as data, and a permission check plus limits for the real world. The trade-off I’d name is that nearly all the speed comes from copies of immutable content sitting in places I don’t directly control, which is wonderful until a paste has to disappear. With more time I’d work deletion and takedown through end to end, and I’d look at streaming large bodies through rather than buffering a few megabytes in memory on the way past.

What this teaches

Learn system design by building a text-paste service like Pastebin step by step. An interactive guide covering unique key generation, separating metadata from blob storage, caching and CDN for read-heavy traffic, TTL expiration, privacy, and async analytics.

Key takeaways

  • Create/read over an API, with text in a blob store and a pointer in the DB.
  • Base62 keys from a Key Gen Service — unique by construction.
  • A Redis cache makes the read-heavy, immutable path sub-millisecond.
  • A CDN serves pastes from the edge for global readers.
  • TTL-based expiry (lazy delete + sweep) keeps storage from filling with dead pastes.
  • Per-paste privacy flags, size caps and rate limits for the real world.
  • Async analytics and a sharded metadata DB keep the read path flat at scale.

Concepts covered

  • What is Pastebin?
  • Store text, return a key
  • Mint a unique key
  • Cache hot pastes
  • Go global with a CDN
  • Expiration & TTL
  • Privacy & limits
  • Analytics, async
built to be pasted, not memorized — make the calls, drop the cache, run the gauntlet.
Finished this one? 0 / 65 System Designs done

Explore the topic

See this alongside everything else on the same subject — handbooks, system designs, challenges and tools, in one place.

More System Designs