Design Spotify
Spotify streams recorded music to a listener on demand. Its catalogue holds 100,000,000 tracks, and a press of play must start sound fast.
The ask
A listener searches the catalogue, presses play and hears music. Playlists, albums and followed artists organise the listening.
Sound must start fast and never stutter. A stream that pauses mid-song has failed, even if it started well.
Listening happens on moving phones and weak connections. The design expects the connection to change during a song.
Offline copies are part of the ask. A downloaded track plays without a connection, under the licence stored with it.
Estimate the scale
The catalogue holds 100,000,000 tracks. One track file takes 10 MB.
100,000,000 tracks x 10 MB = 1,000,000,000 MB of catalogue.
That total makes 1 PB of stored music.
Plays reach 1,000,000,000 a day.
1,000,000,000 plays / 86,400 seconds = about 11,574 plays per second.
Writes are rare beside plays. New tracks arrive in batches, while plays never stop.
API and data
A track record holds the track ID, title and artist. It also holds the length and the stored file's location.
The play operation takes a track ID and a quality level. It returns a short-lived address for the audio file.
A playlist record holds an owner and an ordered list of track IDs. Playlists store IDs, never copies of audio.
A play event records the listener, the track and how long it played. Events feed counts, charts and payments to artists.
A search operation takes text and returns tracks, albums and artists. Results return in pages, tracks first.
High-level design
Audio files live in blob storage. Delivery rides the CDN, so most plays read from an edge near the listener.
A catalogue service owns track records and search. Search runs over an inverted index of titles and artist names.
A playlist service owns lists and follows. It stays separate from the catalogue because lists change fast and tracks change slowly.
Play events flow into a stream for counting. Counting never sits on the path that starts the sound.
How a play runs
The app asks for the track's file address. The service checks the account, then returns a short-lived address for the edge copy.
The edge serves the first part of the file at once. The rest streams while the first part plays.
Quality follows the connection. A weak connection gets a smaller file, and the song does not stop.
The next track preloads near the end of the current one. A gap between songs feels like a failure.
Progress reports back as play events. Pauses, skips and finishes each become an event on the stream.
Deep dive: a catalogue too big for every edge
The full catalogue is 1 PB. No edge can hold it all.
Popular tracks sit at every edge. Rare tracks sit in a few regions and travel further when asked.
The edge asks the origin on a miss and keeps the file afterwards. A rising track spreads across edges on its own.
Storage at the edge follows play counts. A track nobody plays near an edge gives its space to one that is played.
Deep dive: counting a play
A press of play is not yet a play that counts. In this design, a play counts after 30 seconds of listening.
A fast skip carries meaning too. It tells the service the pick was wrong for that listener.
Events can arrive late or twice from a moving phone. Counting removes duplicates by event ID, so a retry never counts two plays.
Counts settle in batches for payment. Live charts read the same stream with a small delay.
Playlists and sharing
A playlist read is a list of track IDs. The app resolves IDs against the catalogue cache in one batch.
A shared playlist shows the same IDs to every viewer. A track removed from the catalogue shows as unavailable, not as a hole.
Follows and playlist changes are small writes. They shard by owner, so one busy account never blocks another.
Evaluation and trade-offs
Delivery through a CDN trades storage copies for start speed. The hot part of the catalogue exists many times over, on purpose.
Counting off the play path trades instant totals for reliable starts. Charts lag a little, and songs do not.
Quality levels trade file size against sound quality. Keeping several sizes of each track costs storage and saves streams.
The catalogue grows slowly and reads never stop. The design favours read paths at every choice.
Spotify in numbers
| Item | Figure |
|---|---|
| Tracks in the catalogue | 100,000,000 |
| One track file | 10 MB |
| Catalogue size | 1,000,000,000 MB |
| Plays a day | 1,000,000,000 |
| Plays a second | 11,574 |
Exercise
Why does the catalogue not sit in full at every edge?