Blog 20 — Instagram: Scaling to 1 Billion Users

C

Qubits of DPK

March 21, 2026

Core Case Studies
Core Concept: PostgreSQL sharding strategy, Photo storage with S3 + CDN, Denormalization for feed performance, Cassandra for activity feeds
Why SDE-2 Critical: Most commonly asked system design question in Indian product company interviews
Status: Draft notes ready

Quick Revision

  • Problem: Serve uploads, feeds, and notifications for a media-heavy social app.
  • Core pattern: S3 plus CDN for media, sharded PostgreSQL for metadata, Cassandra for activity streams.
  • Interview one-liner: Instagram scales by matching storage technology to each access pattern instead of forcing one database everywhere.

️ Architecture Overview

javascript
QUBITS OF DPK
1User uploads photo
234API ServerMedia Service
5  ├── Resize to multiple resolutions (thumbnail, medium, original)
6  └── Store all versions in S3
789CDN (CloudFront) serves photos globally
10
11User metadata, follows, likes → PostgreSQL (sharded)
12Activity feed (notifications)Cassandra
13Session data, counts → Redis

Core Concepts

Photo Storage Architecture

javascript
QUBITS OF DPK
1Upload flow:
2  1. Client uploads to Instagram server
3  2. Server generates photo ID (Snowflake ID — timestamp-based)
4  3. Original stored in S3
5  4. Background job creates 3 resolutions:
6     thumbnail: 150x150
7     medium: 612x612
8     standard: 1080x1080
9  5. All 3 versions stored in S3
10  6. S3 URLs cached in CDN (CloudFront)
11
12Why multiple resolutions?
13  Thumbnail in feed: saves bandwidth for users scrolling
14  Full res only loaded when photo tapped
15  Mobile users on 2G get smaller images automatically

PostgreSQL Sharding Strategy

javascript
QUBITS OF DPK
1Instagram used PostgreSQL from day 1 (similar to OpenAI!)
2
3Sharding by user_id:
4  users table: shard = user_id % num_shards
5  photos table: shard = owner_user_id % num_shards
6  follows table: shard = follower_user_id % num_shards
7
8Keep related data on same shard:
9  User + their photos + their follows → same shard
10Most queries touch only one shard → no cross-shard JOINs
11
12Snowflake IDs:
13  64-bit: [41 bits timestamp][10 bits shard_id][12 bits sequence]
14  Globally unique without coordination
15  Naturally time-ordered
16  Encode shard information directly in ID

Denormalization for Feed Performance

javascript
QUBITS OF DPK
1Normalized approach (bad for feed):
2  To show like count on photo:
3  SELECT COUNT(*) FROM likes WHERE photo_id = 123
4With billions of likes, this is slow
5
6Denormalized approach (Instagram's way):
7  Store like_count directly on photo row:
8  photo: { id: 123, url: "...", like_count: 45231 }
9
10  When user likes: UPDATE photos SET like_count = like_count + 1
11  When user unlikes: UPDATE photos SET like_count = like_count - 1
12
13  Feed query: SELECT * FROM photos WHERE ... ← no JOIN needed
14  Tradeoff: Counter might be slightly inaccurate under heavy concurrency (OK for likes)

Feed Architecture

javascript
QUBITS OF DPK
1Instagram feed (simplified):
2  Pull model for all users (unlike Twitter's push/pull hybrid)
3
4  User opens feed:
5  1. Get list of users Alice follows (from follows table)
6  2. For each followee: get their last N posts
7  3. Merge and sort by timestamp
8  4. Cache result in Redis (TTL: 10 minutes)
9
10  Why pull works for Instagram:
11Photo feed doesn't need sub-second freshness
12Users check feed every few minutes, not seconds
13Simpler than Twitter's fanout complexity
14
15  For super-celebrities: pre-compute partial feed, merge at read time

Cassandra for Activity Feed (Notifications)

javascript
QUBITS OF DPK
1Notifications are time-series data:
2  "Alice liked your photo at 10:00"
3  "Bob commented at 10:01"
4  "Charlie followed you at 10:02"
5
6Perfect for Cassandra:
7  Partition key: user_id
8  Clustering key: notification_timestamp DESC
9Get last 20 notifications: single partition read, extremely fast
10
11Why not PostgreSQL for notifications?
12  10B users × 100 notifications each = 1 trillion rows
13  PostgreSQL can't handle this volume efficiently
14  Cassandra scales linearly: add nodes, add capacity

Scale Achieved

5 Interview Questions This Blog Unlocks

Q1. Design Instagram

Answer: Photo storage: S3 + CDN (multi-resolution). Metadata: PostgreSQL sharded by user_id with Snowflake IDs. Feed: pull model with Redis cache (TTL 10 min). Notifications: Cassandra (time-series). Likes/comments: denormalized counters on photo row. Follows: adjacency list in sharded PostgreSQL.

Q2. How would you design a photo upload system that handles millions of uploads per day?

Answer: Client uploads to API server → store original in S3 → publish event to Kafka → background job resizes to multiple resolutions → store all versions in S3 → update CDN. Async processing prevents blocking the upload API. Return photo ID immediately, versions ready within seconds.

Q3. What is a Snowflake ID and why is it better than auto-increment for distributed systems?

Answer: 64-bit ID encoding timestamp + shard ID + sequence. Globally unique without central coordination (no single ID generator needed). Naturally time-ordered (can sort by ID = sort by creation time). Shard ID encoded in ID — routing without looking up metadata. Auto-increment requires central lock, doesn't scale.

Q4. How does Instagram count likes without a SELECT COUNT(*) query?

Answer: Denormalization. Store like_count directly as a column on the photo row. Increment on like, decrement on unlike (atomic UPDATE). Feed query reads count directly from photo row — O(1). Trade-off: under extreme concurrency, count might be slightly off (race condition). Acceptable for likes. Not acceptable for inventory.

Q5. How does Instagram decide between PostgreSQL, Cassandra, and Redis for different data types?

Answer: PostgreSQL: relational data needing JOINs and transactions (users, photos, follows, comments). Cassandra: time-series data at extreme scale with simple access patterns (notifications, activity feeds). Redis: ephemeral fast data needing sub-millisecond access (sessions, feed cache, counters, rate limits). Match data structure to access pattern.

Key Engineering Lessons