1. The Headline
Serving billions of images with zero perceived loading time.
Instagram's core product is entirely visual. If images take too long to load as a user scrolls through their feed, engagement plummets. They had to build an architecture capable of ingesting millions of massive smartphone photos, processing them instantly, and serving them globally.
2. Requirements and Constraints
Functional Requirements:
- Upload high-resolution photos and apply filters.
- Display an infinite scrolling feed of images and videos.
- Display ephemeral "Stories" that auto-advance.
Non-Functional Requirements:
- Storage: Must store petabytes of immutable image data forever.
- Latency: Images must load near-instantly when scrolling.
- Device Support: Must support everything from 4K retina displays to low-end Androids on 3G connections.
The Ultimate Constraint: You cannot serve the original 12-megapixel (5MB) photo uploaded by the user to everyone who views it. If you do, mobile data plans will be exhausted in minutes, and the app will feel incredibly slow. Images must be aggressively processed and tailored to the exact screen size of the viewing device.
3. The Naive Design & Where It Breaks
A naive approach to image hosting:
- User uploads an image via an API.
- The server saves the file to AWS S3, and saves the S3 URL in a PostgreSQL database (
users -> posts). - When a follower opens the feed, the frontend queries the database, gets the S3 URL, and puts it in an
<img src="...">tag.
Where this breaks under Instagram's load:
- Payload Size: The follower downloads a 5MB image just to view it in a 400x400 pixel square on their phone screen. This wastes massive bandwidth and slows down rendering.
- CDN Misses: Fetching directly from S3 is slow. Even with a CDN, if the image isn't requested frequently in a specific region, the CDN will experience a cache miss and fetch from the origin (S3), adding hundreds of milliseconds of latency.
- Database Bottleneck: Storing billions of rows linking to images in PostgreSQL will cause the database to run out of RAM for its indexes, leading to catastrophic disk thrashing.
4. The Real Architecture: Layer by Layer
Normal operation: The client streams video from the CDN and maintains a persistent WebSocket/MQTT connection for real-time scores.
The Ingestion Pipeline
When a user uploads a photo, it enters an asynchronous processing pipeline (originally using Celery/RabbitMQ).
- The pipeline immediately normalizes the image (strips EXIF data, corrects rotation).
- It generates multiple resolutions of the same image (e.g., thumbnail, 320w, 640w, 1080w) and compresses them heavily (JPEG/WebP).
- These variants are pushed to cold storage (like Amazon S3 or Facebook's custom Haystack storage).
The ID Generation System
To solve the database bottleneck, Instagram created a custom, highly efficient Sharded ID generator using PostgreSQL (and later Facebook's TAO). Instead of UUIDs, they generate 64-bit IDs where the first 41 bits represent a timestamp. This allows images to be sorted chronologically without needing a separate database index on a timestamp column, saving massive amounts of memory.
The Content Delivery Network (CDN)
Images are never served from the origin database. They are pushed to a global CDN (like Akamai or Facebook's edge nodes). When a user in Tokyo requests an image uploaded by someone in New York, the image is served from a server physically located in Tokyo.
5. The Hard Problem
The "Cold Start" of the Feed.
Even with a CDN, if a user opens the app and their feed contains 10 new posts, the frontend has to establish HTTP connections to download 10 images. If the network is slow, the user stares at empty gray boxes.
6. What This Means for the Client (Frontend)
To achieve "zero perceived latency," the Instagram frontend (both React Native and Web) employs aggressive prefetching and responsive rendering.
The Responsive <picture> / srcset
The backend generated multiple resolutions of the image during upload. The frontend leverages this by using the srcset attribute (or native equivalents).
<img
srcset="img-320w.jpg 320w, img-640w.jpg 640w, img-1080w.jpg 1080w"
sizes="(max-width: 600px) 100vw, 600px"
src="img-640w.jpg"
/>The browser or OS calculates the device's screen width and pixel density (DPR), and automatically downloads the smallest possible image that will look sharp. A cheap Android downloads the 320w version (30kb), while an iPhone Pro downloads the 1080w version (150kb).
Progressive JPEGs & BlurHash
Before the actual image downloads, the frontend must render a placeholder. Instagram pioneered techniques like embedding a tiny, 200-byte BlurHash (a string of characters representing the colors of the image) directly in the initial JSON API response. When the feed loads, the frontend instantly decodes the BlurHash into a blurry gradient placeholder. This provides immediate visual feedback while the actual image downloads in the background.
Aggressive Prefetching
When viewing a feed or Stories, the client doesn't wait for the user to scroll to load the next image. It eagerly fetches the next 3-5 images in the queue invisibly in the background. By the time the user swipes to the next Story, the image is already sitting in the device's RAM, rendering instantly.
7. Failure Modes & Graceful Degradation
- Upload Failures: If the user's connection drops during upload, the image is cached locally and the app silently retries in the background (Background Sync) until it succeeds.
- Feed Failure: If the API fails to load new posts, the app seamlessly falls back to a locally cached version of the feed (SQLite / IndexedDB), allowing the user to view previously downloaded images rather than showing an error screen.
8. Numbers & Tradeoffs
- Architecture: Asynchronous processing pipelines to edge CDNs.
- Tradeoff: Storing 5 different sizes of every photo massively increases storage costs on S3. However, storage is cheap, whereas outbound bandwidth (CDN egress) and user latency are expensive. Wasting disk space to save bandwidth and improve UX is the correct tradeoff.
9. How to Use This in an Interview
If an interviewer asks you to design Instagram, Pinterest, or an image-heavy e-commerce site:
"For the backend, we must never serve user-uploaded images directly. We need an asynchronous pipeline to strip metadata, compress, and generate multiple resolutions, pushing the results to a global CDN."
"For the frontend, we must utilize
srcsetto ensure devices only download the resolution they strictly need. To improve perceived performance, we should include a BlurHash or low-quality image placeholder in the initial JSON payload, and aggressively prefetch images that are just below the fold."
10. Sources
- Making Instagram.com faster
https://instagram-engineering.com/making-instagram-com-faster-part-1-62cc0c327538 - Sharding & IDs at Instagram
https://instagram-engineering.com/sharding-ids-at-instagram-1cf5a71e5a5c