CDN Setup for Mobile App Content Delivery
Without CDN a request for a profile image from Minsk goes to a server in Amsterdam or Singapore — 80–150 ms just on RTT, without counting server response time. CDN caches content on the node nearest to the user. For a mobile app with media content this is the difference between feeling "fast" and "slow".
What Goes Through CDN, What Doesn't
CDN makes sense for static or rarely changing content: images, avatars, videos, PDFs, OTA updates, game resource updates (Addressables, Asset Bundles). Dynamic API requests through CDN aren't cached in standard configuration — they need an API Gateway or Edge Functions.
Important: personal user data (documents, private photos) through public CDN with long TTL — risk. For such files use Signed URLs with short lifetime.
Provider Selection
| Provider | Strengths | When to Choose |
|---|---|---|
| Cloudflare CDN | Free tier, simple setup, DDoS protection | Startup, limited budget |
| AWS CloudFront | Native S3 integration, Lambda@Edge | Infrastructure already on AWS |
| Google Cloud CDN | GCS, GKE integration | Infrastructure on GCP |
| BunnyCDN | Low price, good speed in CIS | CIS audience, cost matters |
| Fastly | Edge computing, Varnish under hood | Complex caching rules needed |
For audience in Russia and CIS check for POP nodes in Moscow and St. Petersburg — not all major CDNs have them now.
Caching Setup
TTL strategy depends on content type:
-
User avatars: short TTL (1–24 hours) + versioning via query string (
?v=hash) or path (/avatars/v2/user-123.jpg) - Static app resources (icons, backgrounds): long TTL (30–365 days) + cache-busting via hash in filename
- Video content: streaming via Range requests, medium TTL
Cache-Control: public, max-age=2592000, immutable — for resources with hash in name. immutable tells browser and HTTP client not to check freshness until max-age expires.
On mobile app side: OkHttp on Android caches responses if server sends correct headers. Cache configuration with 50–100 MB disk + CacheControl when building requests allows offline work with cached content.
On iOS: URLCache with diskCapacity 100 MB. For media — NSURLRequest.CachePolicy.returnCacheDataElseLoad.
Invalidation and Purge
CDN caches by URL. Changing file without changing URL doesn't update cache until TTL expires. Three approaches:
-
Versioned URLs (
/assets/logo-a1b2c3d4.png) — best, no manual purge needed -
Query string versioning (
/assets/logo.png?v=42) — simpler, but some CDNs ignore query string in caching (need to explicitly enable) - Manual purge via API — for urgent replacements. Cloudflare, AWS CloudFront, BunnyCDN have APIs, integrate into CI/CD pipeline
Monitoring
After setup check:
- Cache Hit Ratio in CDN dashboard — target 90%+. If lower — TTL too short or too many unique URLs
- Bandwidth savings — how much traffic CDN serves vs origin
- P95 latency by regions — ensure target markets get speedup
In mobile app log X-Cache response header (if CDN provides it) to analytics — see real hit rate from client perspective.
Timeline: one to two business days for basic configuration. Complex rules (Edge Functions, geo-routing, Signed URLs) — three to five days.







