Skip to content
C Codeloom
AWS

AWS CloudFront CDN Tutorial: Caching at the Edge

Learn how AWS CloudFront accelerates content delivery, what cache behaviors look like, and how to wire it up to an S3 origin with sensible defaults.

·4 min read · By Codeloom
Intermediate 10 min read

What you'll learn

  • How CloudFront works at the edge
  • Origins vs cache behaviors
  • TTL and cache key strategy
  • Invalidations and versioning
  • Signed URLs for private content

Prerequisites

  • Familiar with terminals and YAML

What and Why

CloudFront is AWS’s global content delivery network. It places copies of your assets in hundreds of edge locations so users get bytes from a nearby Point of Presence instead of crossing oceans to hit your origin. The result is lower latency, lower origin load, and lower egress costs because CloudFront-to-internet bandwidth is cheaper than S3-to-internet in many regions.

You should reach for CloudFront when you serve static assets, stream video, front a single-page app, or want a global entry point that can do TLS termination, WAF, and request shaping before anything reaches your origin.

Mental Model

Think of CloudFront as a distributed reverse proxy with a TTL-based cache. A request hits an edge node. If the object is cached and fresh, the edge returns it. Otherwise the edge fetches from an origin (S3, ALB, custom HTTP), stores the response, and returns it to the user.

User -> Edge POP -> Cache?
                     |--- HIT -> return bytes
                     |
                     +--- MISS -> Origin Group
                                     |
                                     +-> S3 (/static/*)
                                     +-> ALB (/api/*)
CloudFront request flow with two origins

Two key concepts: an origin is the upstream server, and a cache behavior is a path pattern plus a cache policy. Behaviors are evaluated in order, like a routing table.

Hands-on Example

Let’s create a distribution that fronts an S3 bucket for static assets and an ALB for the API. Using the AWS CLI:

aws s3api create-bucket --bucket my-app-assets --region us-east-1
aws s3 cp ./dist s3://my-app-assets/ --recursive \
  --cache-control "public,max-age=31536000,immutable"

Then a distribution config (trimmed):

{
  "Origins": [
    { "Id": "s3-assets", "DomainName": "my-app-assets.s3.amazonaws.com",
      "S3OriginConfig": { "OriginAccessIdentity": "" } },
    { "Id": "alb-api", "DomainName": "api.example.com",
      "CustomOriginConfig": { "OriginProtocolPolicy": "https-only" } }
  ],
  "DefaultCacheBehavior": {
    "TargetOriginId": "s3-assets",
    "ViewerProtocolPolicy": "redirect-to-https",
    "CachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6"
  },
  "CacheBehaviors": [
    { "PathPattern": "/api/*", "TargetOriginId": "alb-api",
      "ViewerProtocolPolicy": "https-only",
      "CachePolicyId": "4135ea2d-6df8-44a3-9df3-4b5a84be39ad" }
  ]
}

The default behavior caches assets aggressively. The /api/* behavior uses the managed CachingDisabled policy so dynamic responses pass through.

For deploys, fingerprint your assets (app.ab12cd.js) and treat them as immutable. Only invalidate index.html:

aws cloudfront create-invalidation --distribution-id E123 --paths "/index.html"

Common Pitfalls

  • Caching auth-protected responses. Without forwarding the Authorization header in the cache key, two users may see each other’s data. Use a cache policy that includes the headers you key on, or disable caching for that behavior.
  • Slow invalidations. Each invalidation costs money and propagation takes minutes. Versioned filenames make invalidations unnecessary for assets.
  • Origin shielding off. For a small origin, enabling Origin Shield consolidates edge misses through one regional cache, drastically reducing origin traffic.
  • Mixing HTTP and HTTPS origins. Always use https-only to origins; otherwise you leak traffic and break HSTS guarantees.

Production Tips

  • Use Response Headers Policies to inject Strict-Transport-Security, Content-Security-Policy, and X-Content-Type-Options centrally.
  • Put AWS WAF in front of CloudFront for rate limiting and bot rules. It runs at the edge and is cheaper than running WAF on an ALB per region.
  • Watch the CacheHitRate metric. Anything below 80 percent for static assets means you have an unbounded cache key (often query strings or cookies).
  • For SPAs, configure a custom error response: map 403/404 from S3 to /index.html with status 200 so client-side routing works.
  • Use CloudFront Functions for cheap, ultra-low-latency rewrites (a few milliseconds, no cold start). Reach for Lambda@Edge only when you need Node.js APIs or larger logic.

Wrap-up

CloudFront is one of the highest leverage services in AWS: a single distribution can shave hundreds of milliseconds off page loads worldwide and reduce origin cost by an order of magnitude. Start with sensible managed cache policies, version your assets, separate static and dynamic behaviors, and measure the cache hit rate. Once that loop is healthy, layer on WAF, response headers, and edge functions for security and personalization without paying a latency tax.