CloudFront Cache — Why Deploys Never Reach Users
Old app.js served for 24 hours after deploy because cache TTL hadn't expired.
20+ years shipping production infrastructure and CI/CD at scale. Everything here is grounded in real deployments.
- CloudFront caches at 450+ edge locations, serving content from nearest edge. Route 53 provides latency-based, geolocation, and failover DNS routing.
- Together: Route 53 sends users to closest CloudFront edge; CloudFront serves cached content, falling back to origin only on cache miss.
- Performance impact: 100ms latency reduction improves conversion by 1% (Amazon internal data). Global CDN cuts load time from 2.5s to 400ms.
- Production trap: Cache invalidation costs money and takes minutes. Versioned filenames (app.abc123.js) are free and instant.
- Hidden killer: ACM certificates for CloudFront MUST be in us-east-1. Cert in eu-west-1 = distribution fails to create.
- Biggest mistake: Forgetting health checks on Route 53 failover records. Without them, primary fails, traffic never switches.
Imagine your website is a pizza restaurant with one kitchen in New York. If someone in Tokyo orders a pizza, it takes forever to arrive. CloudFront is like opening pizza pickup counters all over the world — customers grab a hot slice from the nearest counter instead of waiting for New York. Route 53 is the smart GPS that tells every customer exactly which counter is closest to them. Together, they make sure your website loads fast no matter where on Earth your user is sitting.
Developers love the shiny new feature. They hate the 12-second DNS propagation, the SSL mismatch errors, and the fact that their global users see a 5-second load time because CloudFront skipped Route 53’s routing policy. Without a tight CloudFront and Route 53 handshake, your deployment is a gamble—users get routed to the wrong region, cache misses stack up, and origin traffic bleeds cash. This stack isn’t just about speed; it’s the critical bridge between DNS resolution and edge distribution that, when configured wrong, silently kills your user experience and your budget.
Why CloudFront + Route53 Means Your Deploy Never Reaches Users
CloudFront is a content delivery network (CDN) that caches responses at edge locations worldwide. Route53 is AWS's DNS service. Together, they form the front door of most production web applications. The core mechanic: Route53 resolves your domain to a CloudFront distribution, and CloudFront serves cached content from edge caches — meaning requests never hit your origin server unless the cache misses. This is great for latency and origin load, but catastrophic for deployments: after you push new code, users still see the old cached version until the TTL expires or you explicitly invalidate the cache. CloudFront caches based on the URL and query string by default — not on headers like version or ETag unless you configure it. The default TTL is 24 hours. That means a deploy at 10 AM won't be visible to most users until the next day. You must either set shorter TTLs (e.g., 1 minute) for dynamic paths or use cache invalidation (costs money per path) or versioned URLs (e.g., /static/v2/main.js). The practical takeaway: CloudFront is not transparent — it actively hides your changes from users until you tell it to stop.
CloudFront + Route 53 Integration — The Global Delivery Stack
CloudFront and Route 53 solve different problems. CloudFront is a CDN — it caches content at edge locations and serves users from the nearest edge. Route 53 is DNS — it translates domain names to IP addresses, but AWS's version goes far beyond basic DNS with latency-based, geolocation, weighted, and failover routing.
Together, they form the global delivery stack: Route 53 directs the user's DNS query to the closest CloudFront edge (latency-based routing). The user's browser then connects to that CloudFront edge. CloudFront serves the content from its cache if available; otherwise, it fetches from the origin (S3, EC2, ALB, or custom HTTP server).
Why this matters: A SaaS company hosted only in us-east-1 with no CloudFront saw 2.5s load times in Australia. After adding CloudFront with a simple cache-all policy, load times dropped to 400ms. That's not theoretical — it's the kind of improvement that directly impacts revenue.
The real value isn't just speed. It's resilience. When your origin goes down in us-east-1, CloudFront can still serve stale content from its cache for hours. That's the difference between a 5-minute outage and a non-event. Route 53's health checks then detect the failure and reroute new requests to a replica in another region.
Route 53 Routing Policies: Latency, Geolocation, and Failover
Route 53 offers several routing policies that go far beyond simple DNS resolution.
Latency-based routing: Route 53 measures round-trip time between the user's resolver and each AWS region where you have an endpoint. It returns the IP of the region with the lowest latency. Ideal for active-active setups where you want automatic performance optimisation.
Geolocation routing: Routes users based on their geographic origin (continent, country, or state). Useful for compliance (GDPR privacy notice for EU users) or content localization (different pricing per country). Note: geolocation uses requestor's IP, not DNS resolver location.
Weighted routing: Distributes traffic across multiple endpoints based on assigned weights. Great for canary deployments (1% traffic to new version) or A/B testing.
Failover routing: Works with Route 53 health checks. If the primary endpoint fails health check, Route 53 returns the secondary endpoint's IP. Ensure health check intervals are short enough for your desired RTO.
Production nuance: DNS caching at ISPs can override Route 53 decisions. Set TTL low (60s) for latency and failover records to respond quickly to network changes.
Another nuance: latency-based routing works at the resolver level, not the end user. If a user's corporate DNS resolver is in Virginia but the user is in Europe, they get routed based on Virginia's latency. That's why geolocation can be more predictable for compliance use cases.
- Latency routing is reactive: uses actual network measurements to find fastest region.
- Geolocation is deterministic: based on IP address ranges, not real-time latency.
- Failover routing requires health checks on EVERY endpoint — without them, failover never triggers.
- Alias records (pointing to AWS resources) are free and support health evaluation.
- Weighted routing is perfect for canary deployments: shift 1% traffic, monitor, then ramp up.
Custom Domain Setup: SSL Certificates, Regions, and Aliases
To serve your app via CloudFront with a custom domain, you need three pieces that must match exactly.
SSL/TLS certificate must be in ACM (AWS Certificate Manager) in the us-east-1 region — even if your origin is elsewhere. CloudFront operates globally but validates certificates from us-east-1 only. The certificate must include all alternate domain names you plan to use (e.g., example.com and www.example.com).
CloudFront distribution must have the custom domain listed in Alternate Domain Names (CNAMEs). This tells CloudFront which domain names to accept traffic for and which certificate to use.
Route 53 alias record pointing to the CloudFront distribution's DNS name (e.g., d123.cloudfront.net). Alias records are free, work at the zone apex, and support health evaluation.
The trap that catches everyone: ACM certificate in eu-west-1 (where your EC2 is) works for ALB but fails for CloudFront. The error message is cryptic: 'The specified SSL certificate doesn't exist, isn't in us-east-1, or doesn't match the alternate domain names'. Always request CloudFront certificates in us-east-1.
Also: if you change the CloudFront distribution (e.g., add a new origin), edge locations can take 10-20 minutes to propagate the configuration. Plan a maintenance window for changes that affect routing.
curl -I https://yourdomain.com before pointing production traffic.Security: Origin Access Control, WAF, and Signed URLs
CloudFront provides several security layers beyond basic TLS.
Origin Access Control (OAC) — restricts access to your S3 origin so that only CloudFront can fetch objects. OAC replaces the older Origin Access Identity (OAI) and is strongly preferred for new distributions. You attach an OAC to the distribution's origin and update the bucket policy to allow requests signed by that OAC. OAC supports server-side encryption with KMS; OAI does not.
AWS WAF integration — associate a Web ACL with your CloudFront distribution to block malicious traffic (SQL injection, XSS, IP reputation lists, rate limiting) before it reaches your origin. WAF rules are applied at the edge, reducing origin load. WAF costs scale with request volume, so use rate-based rules to limit costs.
Signed URLs and Signed Cookies — for premium content, generate time-limited URLs that CloudFront verifies using a private key. Signed URLs are per-file; Signed Cookies apply to a set of files. Generate short expiration (minutes to hours) and combine with IP restrictions for defense in depth.
Field-Level Encryption — encrypts sensitive data (credit card numbers, PII) before sending to the origin, so even the origin cannot read the raw data. The origin receives only the encrypted value.
Real risk: If you use OAI instead of OAC, you cannot use AWS KMS to encrypt objects at rest in S3. Always choose OAC for new distributions.
Production Performance: Cache Hit Ratio, Origin Shield, and Cost Optimisation
CloudFront's effectiveness is measured by cache hit ratio — percentage of requests served from edge cache rather than origin. Target >90% for static assets. Low hit ratio means your cache key is too specific (forwarding unique headers or query strings) or TTL is too short.
Origin Shield — an additional caching layer in a single region that sits between edges and origin. It aggregates requests from all edges, reducing connections to your origin. Enable it for origins that are not already behind a CDN and for high-traffic workloads. Origin Shield can dramatically reduce origin load during traffic spikes.
Regional Edge Caches — automatically enabled for all distributions (as of 2024+). They sit between edge locations and origin, caching content not requested frequently enough to stay in edge caches. No extra cost.
Cost optimisation: CloudFront charges per request and per GB transferred. Use compression (gzip/brotli) to reduce bytes. Brotli compresses text 20-25% better than gzip. Set appropriate TTLs to avoid frequent origin fetches. Use cost allocation tags to track spend per distribution.
Monitoring: CloudWatch metrics include Requests, BytesDownloaded, TotalErrorRate, and CacheHitRate. Set alarms for error rate >1% and cache hit rate <80%. Monitor OriginLatency for signs of origin overload.
Pricing nuance: CloudFront has free tier (1TB transfer/month), but costs can spike if you serve large files (video) or have high request rates (many small files). For small files, per-request cost dominates; consider combining files into archives or using HTTP/2 multiplexing.
Requests to detect unexpected traffic spikes.What the Hell is Route53 Actually Doing?
Route53 is not magic. It's a DNS service with a global anycast network and a health-check engine strapped to the side. When a client hits your CloudFront distribution, Route53 translates the human-readable domain into an IP — but that's the boring part.
The real power is the latency-based routing. Route53 maintains a latency map between every AWS edge location and your origins. When a user in São Paulo requests your site, Route53 doesn't just serve any old IP. It looks up which CloudFront edge is closest to that user's resolver, returns that IP, and your content travels the shortest possible path. That's why your global users don't hate you.
But here's the trap: Route53's health checks are optional per record. If your CloudFront distribution goes down, Route53 will keep returning the same IP unless you configure failover routing with active health checks. Without them, you're serving dead endpoints. Production incident waiting to happen.
Prerequisites — The Things You'll Hate Yourself For Skipping
Before you touch a single Route53 record, get these sorted. I've seen production deploys stall because some junior didn't have the domain transferred or forgot about DNS TTL propagation. Don't be that person.
You need: an active AWS account (obviously), a registered domain — either through Route53's registrar or a third-party like Namecheap. If it's third-party, make sure the nameservers are pointed to AWS. That means four NS records from your registrar pointing to the Route53 hosted zone's delegation set. Get this wrong and your domain won't resolve. Happens weekly.
DNS concepts aren't optional. You need to understand TTL, A/AAAA records, CNAME, and alias records. Especially alias records — they're Route53's killer feature for CloudFront. Unlike CNAME, alias records work at the zone apex (example.com, not www.example.com) and cost nothing extra. Use them.
Finally, have your SSL/TLS certificate ready — ideally in AWS Certificate Manager in us-east-1. CloudFront only loads certificates from us-east-1. Request it there, not in your app's region. That mistake has cost teams days of debugging.
Gradual Cutover Strategy: DNS Weighting and Dual-Origin Migration
Changing DNS records for a production CloudFront distribution is risky: TTLs are cached globally, and a single misconfigured origin can take down all users before you notice. A gradual cutover avoids this. The why is simple: Route53 lets you attach multiple weighted records to the same alias, splitting traffic between your old origin and the new CloudFront distribution. Start with a 99/1 split, incrementally shift the weight over hours or days while monitoring error rates, cache hit ratios, and latency. This exposes problems in the new origin — wrong S3 bucket policies, stale SSL, or missing CORS headers — before they affect everyone. Route53 health checks can also automatically fail back to the old origin if the new target returns 5xx. Once 100% traffic is stable on CloudFront, delete the old record. This strategy is mandatory for any migration that cannot tolerate downtime or a full rollback.
CloudFormation Infrastructure: Declarative CloudFront + Route53 Pipelines
Manually clicking through the AWS console to set up CloudFront and Route53 is fragile and unrepeatable. CloudFormation turns your entire global delivery stack into version-controlled infrastructure. The why is obvious: one template defines the origin, distribution, SSL certificate, aliases, and Route53 record in a single deploy. Changes are reviewed via pull requests, rolled back via change sets, and auditable in CloudTrail. The key pattern is the CloudFront distribution's DomainName output passed as an alias target to a Route53 RecordSet — both in the same stack. Include a Lambda@Edge associaton for signed URLs or header rewriting without leaving the template. Use nested stacks to separate the WAF, the origin bucket, and the distribution, so you can update security policies independently. This eliminates the most common production errors: mismatched SSL regions, forgotten Origin Access Control, and misconfigured CNAMEs.
Overview: Why CloudFront and Route53 Belong Together
Before you wire a CDN to a DNS provider, ask why they should be coupled at all. CloudFront gives you edge caching and DDoS protection. Route53 gives you global traffic routing. Alone, each solves a different problem. Together, they solve the hardest one: ensuring your users hit the nearest healthy endpoint without manual failover or stale caches. The real value isn't feature stacking—it's eliminating the gap between DNS resolution and content delivery. When Route53 routes a user to a CloudFront edge location, the distance between request and response drops from 200ms to 20ms. More importantly, Route53's health checks can tell CloudFront which origin is alive, so your CDN doesn't serve 502s from a dead server. This isn't about convenience; it's about preventing the scenario where your deployment works but users still see broken pages because DNS cached an old IP. Choose this stack when uptime and speed are non-negotiable, and you need one console to manage both.
Architecture: How the Pieces Actually Fit Together
Stop thinking of CloudFront and Route53 as separate services. In production, they form a single traffic pipeline with three layers. First, Route53 receives a DNS query and applies a routing policy—latency-based, geolocation, or weighted. It resolves to the nearest CloudFront edge location. Second, that edge checks its cache. On a miss, it forwards to the origin through an Origin Access Control (OAC) or custom header. Third, Route53's health probes continuously monitor your origin endpoints and feed their status back to CloudFront via origin failover groups. The architectural trap most engineers fall into: they configure DNS routing to multiple origins but forget CloudFront can only talk to one origin per behavior. The fix is a CloudFront origin group with primary and secondary origins tied to Route53 health checks. This means if your primary origin in us-east-1 fails, the edge fetches from eu-west-1 without any DNS propagation delay. The result: sub-second failover instead of the 60-second TTL hell most teams accept. Always model the pipeline as DNS → edge cache → origin group → health feedback loop.
The Deploy That Never Reached Users — Cache Invalidation Missed
aws cloudfront create-invalidation --distribution-id XYZ --paths /app.js /styles.css
2. Switched to versioned filenames: app.abc123.js generated from content hash. New file → new URL → cache miss automatically.
3. Set short TTL (60s) for HTML files that reference versioned assets.
4. Added monitoring: alert if x-cache header shows 'Hit' for updated file patterns after deploy.
5. For emergency fixes: create invalidation for exact path, wait for completion, verify via curl.- Never rely on TTL expiry for urgent content updates. Invalidation is required.
- Versioned filenames (app.abc123.js) are free, instant, and the industry standard.
- Include cache invalidation as a mandatory step in your deployment pipeline.
- Use curl -I to check x-cache header: 'Miss' means origin fetch, 'Hit' means from edge.
- For static sites, set short TTL (60s) on HTML, long TTL (1 year) on versioned assets.
aws:SourceArn = distribution ARN. OAC replaces legacy OAI.dig +trace yourdomain.com to see propagation. For planned changes, lower TTL to 60s 24 hours before the change.EvaluateTargetHealth is enabled.curl -I https://yourdomain.com/app.js | grep -i x-cacheaws cloudfront create-invalidation --distribution-id YOUR_DIST_ID --paths '/*'Key takeaways
/static/*) for batch updates. Individual paths cost more and take longer.Common mistakes to avoid
7 patternsSetting TTLs too low or using invalidation for every deploy
Forgetting to attach health checks to Route 53 failover records
Requesting ACM certificate outside us-east-1 for CloudFront
Using CNAME instead of Alias record for root domain (example.com)
Not enabling compression on CloudFront distributions
Forwarding all query strings in cache key
Using OAI (Origin Access Identity) instead of OAC for KMS-encrypted buckets
Interview Questions on This Topic
Explain the difference between CloudFront cache invalidation and object versioning. Which would you use and why?
Frequently Asked Questions
20+ years shipping production infrastructure and CI/CD at scale. Everything here is grounded in real deployments.
That's Cloud. Mark it forged?
11 min read · try the examples if you haven't