Difficulty: Tier 1 (warm-up) Asked at: Arbisoft, Educative, Careem, Amazon phone screens Time budget: 45 min
Pastebin is the URL shortener’s slightly bigger sibling: instead of mapping a code to a URL, you map a code to a blob of text (sometimes megabytes). That one change — the payload is large — pulls in object storage, and that’s the whole lesson. If you’ve done the URL shortener, 80% of this transfers; focus on what’s different.
Prerequisites: URL Shortener, Object Storage, CDN
Functional:
Non-functional:
Out of scope: rich collaboration/editing (that’s collaborative editing), accounts, comments.
Size limit: state one — e.g. 10 MB per paste. It bounds storage and informs the design.
Assume 10 million new pastes / month, average size 10 KB (most are small snippets; a few are huge).
🚨 The numbers say: request rates are low, but payloads are large and storage grows fast. So the design centers on cheap durable blob storage + a CDN, not on request throughput.
POST /pastes
body: { content, expiresAt?, visibility?, customPath? }
→ 201 { url: "https://pst.bin/aB3xK9p" }
GET /{pasteId}
→ 200 { content, createdAt, ... } (or the raw text for a raw endpoint)
GET /{pasteId}/raw → 200 text/plain (raw content, CDN-friendly)
DELETE /pastes/{pasteId}
Split metadata from content — the crucial design choice:
Metadata store (small, queried, key-value or relational):
| Field | Type |
|---|---|
paste_id |
string (PK), base-62 code |
content_ref |
string — pointer to the blob in object storage |
size |
int |
created_at / expires_at |
timestamp |
visibility |
enum |
Content store: the actual text lives in object storage (S3/GCS/Blob), keyed by content_ref. 🚨
Don’t put multi-MB blobs in your primary database — it bloats the DB, slows queries, and is far more
expensive per byte than object storage.
flowchart LR
Client -->|POST| LB[Load Balancer]
Client -->|GET| CDN[CDN]
CDN -.miss.-> LB
LB --> App[App Servers]
App --> Meta[(Metadata Store<br/>key-value)]
App --> Blob[(Object Storage<br/>S3 - the paste text)]
CDN -.-> Blob
Write: generate paste_id (same range-based counter trick as the URL shortener), upload the content to
object storage, store metadata (with the content pointer) in the metadata store, return the URL.
Read: the CDN serves popular pastes’ raw content directly from the edge (cache). On miss, the app reads metadata, fetches the blob (or hands back a URL to it), returns it, and the CDN caches it.
Because they have opposite characteristics. Metadata is tiny, structured, and queried (list a user’s pastes, check expiration) — a database’s job. Content is large, opaque, and served whole — object storage’s job (cheap per GB, infinitely scalable, durable, CDN-integrated). Mixing them makes the database huge and slow and wastes money. 🚨 “Metadata in the DB, blobs in object storage” is a pattern you’ll reuse in every design with large payloads (file storage, video, images).
A viral paste (a leaked config, a popular snippet) can get hammered. Because content is immutable once created, it’s perfectly cacheable. Put a CDN in front: the edge serves the raw text, your origin barely gets touched, and global users get low latency. Immutability is what makes this clean — no invalidation needed. (CDN)
expires_at; lazily 404 on read if expired; a background job (or object-storage
lifecycle policy) deletes expired blobs to reclaim space.viewed flag so only one succeeds.For multi-MB pastes, let the client upload directly to object storage via a pre-signed URL rather than streaming the bytes through your app servers. The app issues a pre-signed PUT URL, the client uploads to S3 directly, then confirms — this keeps large payloads off your servers entirely. (Same pattern as file storage.)
paste_id (it’s small, so this is late to bite).| Decision | Chosen | Alternative | Why |
|---|---|---|---|
| Content storage | Object storage (S3) | In the database | Cheap per byte, durable, CDN-ready, keeps DB lean |
| Metadata | Separate key-value store | Combined with content | Opposite access patterns |
| Read scaling | CDN (immutable content) | App-server caching | Immutable blobs cache perfectly at the edge |
| Large uploads | Pre-signed direct-to-S3 | Stream through app | Keeps big payloads off compute tier |