How Spotify starts playing music in under a second
How Spotify uses predictive prefetching, Vorbis/AAC codec switching, local cache management, and crossfade buffering for instant playback.
The scenario
A listener taps a song and expects audio almost immediately, even on a cold cache, a busy cellular connection, or a device with limited storage. Downloading the entire track before playback would make startup slow; starting with an aggressive quality would make stalls more likely.
Music playback is a latency pipeline: resolve the track, authorize access, find a nearby encrypted segment, start with a small safe buffer, and keep downloading future audio while the listener hears the current segment.
30-second mental model
The client predicts what will play next, keeps a small local cache, and requests short encoded chunks from a delivery edge. It starts playback once the first playable data is available, then adapts quality and prefetch depth to measured throughput, buffer health, device constraints, and user settings. Crossfade and gapless playback are local scheduling problems layered on top.
Spotifyβs user-facing behavior is public, but private CDN topology, codec policy, cache hit rates, and exact thresholds vary by client and region. Treat the concrete architecture and numbers below as an illustrative streaming design unless stated otherwise.
5-minute end-to-end flow
- Resolve the track and playback context, check entitlement, and obtain a short-lived authorization for media requests.
- Select an encoded representation and nearby edge, then request only the first segment rather than the whole file.
- Fill a startup buffer, hand decoded audio to the platform audio queue, and begin playback as soon as the startup policy is met.
- Prefetch the likely next track and later segments while respecting storage, battery, and metered-network policy.
- Re-estimate throughput and buffer headroom before each request; step quality down quickly when the buffer drains and back up cautiously.
- Record startup, rebuffer, seek, cache, and quality-switch telemetry without putting user content or credentials in logs.
The Architecture
Here is how a song plays from tap to audio:
- You tap a song. The client checks the local disk cache first. If the first segment is cached, playback starts immediately from disk with zero network latency.
- If not cached, the client resolves the nearest CDN edge PoP through DNS. Because Spotify pre-resolves DNS for audio endpoints, this adds almost no delay.
- The client requests just the first few segments (enough for 2-3 seconds of audio). At 160 kbps, that is roughly 40 KB per second, so the first second of audio is only ~20 KB. On any reasonable connection, this arrives in under 200ms.
- The decoder starts playing as soon as the first segment arrives. It does not wait for the entire file. This is progressive playback, the same principle as video streaming but simpler because audio files are much smaller.
- While the current song plays, the prefetch engine quietly downloads the first 10-30 seconds of the next track in the queue. By the time the current song ends, the transition is seamless.
The key insight: Spotify does not wait for you to take action. By the time you want the next song, the client already has it.
Here is the codec selection logic per platform:
| Platform | Primary Codec | Fallback Codec | Hardware Decode? |
|---|---|---|---|
| Android | Ogg Vorbis | AAC | Software only |
| iOS | AAC | HE-AAC (low bitrate) | Yes (Apple chip) |
| Desktop (Windows/Mac) | Ogg Vorbis | AAC | Software only |
| Web Player | AAC | MP4/AAC container | Browser native |
| Smart speakers | Opus | Vorbis | Varies |
The codec choice is made at connection time, not per-request. The client announces its supported codecs during authentication, and the backend returns audio URLs pointing to the correct codec variant. This avoids any runtime codec negotiation overhead.
Here is a quick back-of-envelope calculation for data consumption:
| Quality Tier | Bitrate | MB per minute | MB per hour | Full 4-min song |
|---|---|---|---|---|
| Low | 24 kbps | 0.18 MB | 10.8 MB | 0.72 MB |
| Normal | 96 kbps | 0.72 MB | 43.2 MB | 2.88 MB |
| High | 160 kbps | 1.2 MB | 72 MB | 4.8 MB |
| Very High | 320 kbps | 2.4 MB | 144 MB | 9.6 MB |
At Very High quality, an hour of listening uses 144 MB. This is relevant for understanding why prefetching decisions matter: aggressively prefetching at 320 kbps burns through mobile data 13x faster than streaming at 24 kbps. The prefetch engine must be bandwidth-aware.
Audio streaming is fundamentally simpler than video streaming. A 320 kbps audio file uses roughly 2.4 MB per minute. A 1080p video at 5 Mbps uses 37.5 MB per minute. This 15x difference is why Spotify can aggressively prefetch entire upcoming tracks while Netflix only prefetches segments.
Predictive Prefetch and Next-Track Buffering
The single biggest reason Spotify feels instant is that it starts downloading the next song before you need it. This is not a simple "download the next file in the queue." The prefetch engine is surprisingly sophisticated.
Think of it like a waiter at a restaurant who starts preparing your dessert before you finish your main course. If they guess right (which they do 85% of the time), the dessert appears the instant you push your plate away. If they guess wrong, there is a slight wait while they prepare something else. The cost of a wrong guess is one wasted dessert prep, not a catastrophe.
The following walk-through covers the three scenarios shown in this diagram:
Scenario 1: Normal transition (Song A to Song B). While Song A plays, the prefetch engine downloads Song B in the background. When Song A reaches its last 5 seconds, the player starts blending the audio: Song A fades out while Song B fades in. The user hears a seamless crossfade with zero gap. This is the happy path and covers roughly 70-80% of all transitions.
Scenario 2: Skip (Song A to Song C). The user presses skip mid-song. Song C was not prefetched (the engine had only prefetched Song B). The client immediately requests Song C from the CDN. Even without prefetch, the first segment arrives in under 200ms because of CDN edge proximity. There might be a barely perceptible gap. Meanwhile, the prefetch engine cancels the Song B download (wasted bandwidth, but minimal) and starts prefetching Song D.
Scenario 3: Cache hit (not shown, but the fastest case). Song A was already in the local disk cache from a previous listen. The client reads it directly from SSD. Playback starts in under 50ms, limited only by the time to read from disk and decode the first segment. This is the ideal path for repeated listening.
The prefetch engine uses several signals to decide what and when to download:
- Queue position: The next 1-2 songs in the explicit queue are always prefetched. This is the simplest case.
- Autoplay predictions: When the queue is empty, Spotify's recommendation engine provides the next 5-10 predicted tracks. The client prefetches the top 1-2.
- Playback progress: Prefetching starts after the user has listened to about 5 seconds of the current track. This avoids wasting bandwidth when someone is quickly skipping through songs.
- Network conditions: On WiFi, the client prefetches more aggressively (full tracks, higher quality). On cellular, it prefetches only the first 30 seconds at a lower bitrate.
The key point: the phrase "adaptive prefetch based on engagement signals" is what separates a good answer from a generic one. It shows you understand the bandwidth-latency tradeoff rather than just the concept.
Prefetching creates a tension with cellular data plans. Spotify lets users set "Data Saver" mode, which disables all prefetching on cellular and forces the lowest bitrate. The prefetch engine must respect this setting, which means the code path forks early: WiFi gets aggressive prefetch, cellular with data saver gets zero prefetch, and cellular without data saver gets conservative prefetch (first 10s only).
Here is a summary of prefetch behavior by network type:
| Network | Prefetch Scope | Quality | Trigger |
|---|---|---|---|
| WiFi | Full next track + partial track after | User's quality setting (up to 320 kbps) | After 5s of current track |
| Cellular (normal) | First 10-30s of next track | 160 kbps max | After 5s of current track |
| Cellular (data saver) | None | 96 kbps | N/A |
| Offline | N/A (all local) | User's download quality | N/A |
So when does this actually matter in an design review? Prefetching is the answer to "why does skipping to the next song feel instant?" If you only talk about CDN latency, you have missed the point. The CDN matters for the first-ever play of a song. For every subsequent interaction (next track, replay, shuffle within a familiar playlist), the prefetch engine and local cache are doing all the heavy lifting.
The rule of thumb: on a healthy connection, the user should never wait for network I/O when transitioning between tracks. The only acceptable wait time is the 200ms first-byte latency for a cache miss on a song they have never heard before.
Local Cache Management Strategy
The local disk cache is the unsung hero of perceived performance. If a song is already on disk, playback starts with zero network latency. The cache management strategy determines what stays and what gets evicted.
The cache lives on the device's internal storage (or SD card on Android if configured). It is not an in-memory cache. It persists across app restarts, device reboots, and even app updates (the cache directory is preserved). This means a user who listens to the same commute playlist every day only downloads those tracks once, regardless of how many times they restart the app.
The cache also stores metadata alongside the audio data: track ID, codec, bitrate, encryption key reference, download timestamp, play count, and checksum. This metadata is stored in a lightweight SQLite database that the cache manager queries when deciding what to evict. The audio data itself is stored as individual encrypted files in a flat directory structure, named by content hash.
Spotify's cache has several layers of priority:
| Priority | Content Type | Eviction Policy |
|---|---|---|
| 1 (never evict) | Offline/downloaded tracks | User must manually remove |
| 2 (high) | Recently played tracks | LRU, kept for 30 days |
| 3 (medium) | Prefetched upcoming tracks | LRU, kept for 7 days |
| 4 (low) | Autoplay predictions | LRU, evicted first |
The cache is encrypted with a device-specific key. This is not just DRM theater. It prevents someone from copying the cached Ogg/AAC files to another device and playing them outside the app. The encryption also means that if the user's subscription expires, the cached files become unplayable without re-authentication.
A common design review mistake is forgetting that cached audio files must be encrypted. Without encryption, the cache becomes a piracy vector. Every major streaming platform encrypts cached content with a device-bound key that requires active subscription authentication to decrypt.
Here is a rough sizing exercise for the cache. These numbers help you ground the discussion in concrete details during an design review:
| Listening pattern | Avg tracks/day | Avg track size (160 kbps) | Daily cache growth | Days to fill 5 GB |
|---|---|---|---|---|
| Casual listener | 10-20 | 4.8 MB | 48-96 MB | 52-104 days |
| Heavy listener | 50-100 | 4.8 MB | 240-480 MB | 10-21 days |
| Playlist repeater | 15 (repeated) | 4.8 MB (cached after day 1) | ~0 after day 1 | N/A |
Notice that playlist repeaters barely grow the cache after the first session. This is why the repeat-detection heuristic matters: it identifies tracks that should never be evicted, freeing cache space for genuinely new listens.
Adaptive Bitrate Selection Under Network Changes
Unlike video (where you switch between visible quality levels), audio bitrate switching is nearly invisible to the listener. Moving from 320 kbps to 160 kbps Ogg Vorbis is noticeable only to trained ears on good headphones. This gives the audio client more leeway than a video player.
The asymmetry is important. When Netflix drops from 4K to 720p, the user sees it immediately and might complain. When Spotify drops from 320 kbps to 160 kbps, most users do not notice at all. This means the audio player can be more aggressive about downgrading quality to prevent stalls, because the perceived cost of downgrading is much lower than the perceived cost of buffering.
Here is the hierarchy of priorities for the audio player (in order):
- Never stall playback (most important). Any audible gap or spinner is a failure.
- Maintain current quality if the buffer is healthy.
- Upgrade quality when extra bandwidth is consistently available.
- Minimize unnecessary switches (quality ping-pong is jarring even if individual switches are not).
This priority ordering drives the state machine design.
The bitrate selector runs as a state machine with hysteresis. The upgrade threshold is higher than the downgrade threshold to prevent oscillation. If you downgrade at 400 kbps, you do not upgrade again until 600 kbps. This 200 kbps gap prevents the "quality ping-pong" effect where the audio keeps switching back and forth.
The client also maintains a playback buffer of roughly 10-30 seconds of decoded audio. As long as this buffer is healthy (above 5 seconds), the player can tolerate brief bandwidth dips without doing anything. The buffer acts as a shock absorber.
The buffer works differently from a video player's buffer. Video buffers store compressed data (H.264/H.265 NAL units). Audio buffers typically store decoded PCM samples because audio is cheap to decode and the decoded data is small. A 30-second buffer of 44.1 kHz stereo 16-bit PCM is about 5.3 MB. This fits easily in memory on any modern device.
Why decode early? Because the critical path for audio playback is the time between "user taps play" and "sound comes out of the speaker." Decoding ahead of time means the audio output callback can pull PCM directly from the buffer without waiting for a decode step. This shaves 5-20ms of latency on every buffer refill.
Here is a breakdown of how the buffer interacts with the bitrate selector:
| Buffer Level | Selector Behavior | Rationale |
|---|---|---|
| > 15 seconds | Consider upgrading quality | Plenty of runway to absorb any bandwidth dip |
| 5-15 seconds | Maintain current quality | Healthy but not enough to risk upgrading |
| 2-5 seconds | Start downgrading quality | Buffer is draining, need to refill quickly |
| < 2 seconds | Force lowest quality, pause prefetch | Emergency mode, dedicate all bandwidth to current track |
| 0 seconds | Playback stalls, show spinner | Worst case. Buffer empty, waiting for data |
The goal is to never reach the bottom two rows. If the system is working correctly, the buffer stays above 5 seconds almost all the time, and stalls are extremely rare (Spotify targets < 0.1% of sessions experiencing any buffering).
The reason Spotify can switch codecs mid-stream (from Vorbis to AAC or vice versa) is that all codecs decode to the same intermediate format: raw PCM samples. The decoder simply swaps which codec pipeline is active, and the downstream audio output sees the same PCM format regardless of source codec.
Bottlenecks, failure modes, and operations
-
Gapless playback between tracks: Two songs on the same album should transition without a gap or click. The encoder strips silence from the end of each track and stores the exact sample offset. The client's crossfade engine uses this metadata to overlap the last few milliseconds of one track with the first few of the next. Getting this wrong (or ignoring it) produces audible gaps that frustrate audiophiles.
-
Skip storms: Some users rapidly skip through 10-20 songs looking for the right one. Each skip triggers a prefetch cancellation (for the old next track) and a new urgent fetch (for the just-selected track) plus a new background prefetch (for the new next track). Without careful request cancellation, you accumulate zombie downloads that waste bandwidth and compete with the track the user actually wants to hear.
-
Offline-to-online transitions: A user boards a subway (loses signal) and the app falls back to cached content. When they emerge, the app needs to seamlessly resume streaming without a gap. This requires the client to track exactly where the cached content ends and where to resume from the CDN. The segment boundaries must align perfectly.
-
Cache corruption: Disk writes can fail silently (power loss, storage full). If a cached segment is corrupted, the decoder produces noise or crashes. Spotify checksums every cached segment and silently re-downloads corrupted ones. The user never knows it happened, but the cache layer must validate integrity on every read.
-
DRM and key rotation: Cached files are encrypted. The decryption key is tied to the user's active session. If the key rotates (login elsewhere, subscription change), cached files must be re-encrypted or invalidated. Doing this lazily (at read time) avoids blocking the UI, but it adds complexity to every cache read path.
-
Free tier ad insertion: Spotify Free users hear ads between songs. The ad audio must be fetched, decoded, and inserted into the playback stream without a jarring gap. The ad insertion engine runs as a separate prefetch pipeline that downloads ad audio during the current song and splices it into the crossfade buffer. If the ad fetch fails (network issue), the client skips the ad rather than blocking playback. This is architecturally distinct from the music prefetch pipeline but shares the same cache and decoder infrastructure.
-
Seek within a song: When a user drags the seek bar to a different position, the client needs to find the correct segment for that timestamp. If the segment is cached, seek is instant. If not, the client calculates the byte offset from the segment map (stored in the track's metadata) and requests just that segment from the CDN. Accurate seeking requires the segment map to include precise timestamp-to-byte-offset mappings, which the encoding pipeline generates during segmentation.
-
Multi-device playback (Spotify Connect): A user starts a song on their phone, then transfers playback to their smart speaker via Spotify Connect. The smart speaker must resume from the exact position. The phone sends the current playback position (timestamp + buffer state) to the Spotify backend, which relays it to the speaker. The speaker then fetches audio from its nearest CDN edge starting at that offset. If the speaker has its own cache and the song happens to be there, it plays from cache. Otherwise it fetches from CDN. The critical detail is that the seek position must account for the crossfade buffer: if the phone is 5 seconds into a crossfade, the speaker needs to start 5 seconds earlier to match the audio state.
-
Codec fallback on decode errors: If the Vorbis decoder encounters a corrupted segment or an unsupported feature, it should not crash the app or play garbled audio. The client catches decode errors and falls back to the next available segment, interpolating a brief silence (10-50ms) to mask the gap. If errors are persistent for a track, the client can re-request the segments at a lower bitrate (which uses simpler encoding parameters and is less likely to trigger edge-case decoder bugs).
Common mistakes and misconceptions
| Mistake | What they say | Why it is wrong | What to say instead |
|---|---|---|---|
| Ignoring the cache | "Spotify streams everything from CDN" | 40-60% of plays are cache hits. Ignoring the cache misses the biggest latency optimization. | "The client checks its local disk cache first. If the track is cached, playback is instant with zero network cost." |
| Treating audio like video | "Spotify uses HLS with adaptive bitrate" | Spotify uses its own protocol, not HLS. Audio segments are much smaller than video and the quality ladder has fewer rungs. | "Audio at 320 kbps is 40 KB/s. A 2-second segment is 80 KB. This lets the client prefetch entire tracks, not just segments." |
| Forgetting prefetch | "The CDN is close so latency is low" | CDN proximity helps, but 100ms per request still adds up. Prefetching eliminates the request entirely. | "By the time the current song ends, the next track is already cached locally. The CDN latency is zero for prefetched content." |
| No mention of encryption | "Files are cached on disk" | Unencrypted caches are a piracy vector. Every streaming service encrypts cached content. | "Cached files are encrypted with a device-bound key. Playback requires active session authentication." |
| Oversimplifying codecs | "They use MP3" | Spotify uses Ogg Vorbis (Android/desktop), AAC (iOS/web), and increasingly Opus. MP3 is not used. | "Spotify encodes each track in Vorbis, AAC, and Opus at three quality tiers. The client picks the codec based on platform and the bitrate based on network." |
Practical checklist
- Measure time to first audio separately from time to full-track download; optimize the former without exhausting bandwidth.
- Start with a conservative representation and a small buffer, then adapt using smoothed throughput and buffer headroom.
- Prefetch only likely next content and respect storage, battery, roaming, and user download settings.
- Keep media authorization, encryption, and cache keys scoped so cached audio cannot become an access-control bypass.
- Make cache eviction explicit: retain recently played material, but cap storage and protect downloads from surprise deletion.
- Test cold cache, seek, network handoff, rate changes, background audio, decoder limits, and partial segment failures.
- Instrument startup, rebuffer, gapless/crossfade accuracy, cache hit/miss, quality switches, and data consumption.
- Treat codec, CDN, and threshold values as client/region policy rather than universal Spotify facts.
Test Your Understanding
Quick Recap
- Spotify encodes every track in multiple codecs (Vorbis, AAC, Opus) at three quality tiers (96, 160, 320 kbps) to match platform and network conditions.
- CDN edge PoPs place audio segments within 50-100ms of most users, but the local disk cache eliminates the network entirely for frequently played and prefetched tracks.
- The prefetch engine downloads the next song in the queue while the current one plays, starting after 5 seconds of confirmed listening to avoid wasting bandwidth on skipped tracks.
- The local disk cache uses weighted LRU eviction with priority tiers: pinned offline tracks are never evicted, and frequently played songs have higher retention than autoplay tracks.
- Adaptive bitrate switching happens mid-stream at segment boundaries with a crossfade, using a hysteresis state machine (downgrade at 400 kbps, upgrade at 600 kbps) to prevent quality oscillation.
- Gapless playback relies on encoder metadata (padding offsets) and client-side crossfade with configurable duration (0-12 seconds).
- All cached files are encrypted with a device-bound key to prevent piracy, and checksummed to detect corruption.
- Skip storms are handled by aggressive request cancellation and a reduced prefetch mode that downloads only 2-3 seconds per track until the user settles.
Related Concepts
- How Netflix prevents buffering on slow networks: The video equivalent of this problem. Netflix faces the same adaptive bitrate challenge but at 15x the data rate, making the tradeoffs more extreme.
- How CDN cache invalidation works: Deep dive into how CDN edge nodes decide what to cache and when to evict, directly relevant to Spotify's audio segment caching.
- How video streaming works: Covers HLS/DASH adaptive streaming protocols that share architectural DNA with audio streaming but with different constraints.
- How the hot key problem happens: Relevant when a viral song creates a thundering herd on specific CDN edge nodes, a real problem Spotify faces during major album drops.
- How push notifications work: The notification that triggers "New album from your favorite artist!" which then triggers millions of simultaneous play requests, connecting the CDN pre-warming strategy to the notification pipeline.