What is CloudFront (CDN)?
Amazon CloudFront is AWS’s CDN (Content Delivery Network). A CDN is a worldwide network of servers that keep copies of your content close to your users, so a person in Tokyo does not have to fetch every image and script from a server in Virginia. CloudFront sits in front of your real server (called the origin), caches what it can at hundreds of edge locations around the globe, and serves repeat requests from the nearest one. It matters because distance equals delay: shaving off a few hundred milliseconds on every asset makes a site feel dramatically faster, while also taking load off your origin.
How CloudFront works
When a user requests a file, their request goes to the nearest CloudFront edge location (a small AWS data center near major cities). If that edge already has a fresh copy of the file in its cache (temporary local storage), it sends it back immediately, this is a cache hit. If not, it is a cache miss: the edge fetches the file from your origin once, sends it to the user, and keeps a copy so the next nearby user gets a hit.
The origin is wherever your content really lives. CloudFront can front almost any HTTP source:
- An Amazon S3 bucket (object storage) for images, videos, and static website files.
- An Application Load Balancer (ALB) or EC2 instance running your app.
- Any public HTTP/HTTPS server, even one outside AWS.
Because requests terminate at the edge, CloudFront also handles TLS (Transport Layer Security, the https:// encryption) for you and absorbs traffic spikes. It is integrated with AWS Shield Standard, which gives free DDoS protection (defense against Distributed Denial of Service attacks that try to flood you with traffic).
When to use CloudFront (and when not to)
| Workload | Good fit for CloudFront? | Why |
|---|---|---|
| Static assets (images, CSS, JS, video) | Yes, ideal | Highly cacheable, served from the edge with near-zero origin load |
| S3-hosted static website | Yes | Adds HTTPS, a custom domain, and global speed to a plain bucket |
| API with cacheable GET responses | Sometimes | Helps only if responses can be reused across users |
| Per-user dynamic API (no-cache) | Usually not | Every request still goes to origin, adding an extra hop |
Gotcha: CloudFront only speeds things up when content is cacheable. If your origin returns
Cache-Control: no-cacheor sets per-user cookies on every response, the edge cannot reuse anything. Each request becomes a cache miss that travels to the origin anyway, plus the extra edge hop, so you can actually add a little latency and get almost no benefit. Use CloudFront for static and shared content; for purely dynamic, personalized APIs, consider it only for TLS termination and DDoS protection, not for caching.
Creating a distribution (overview)
A distribution is the CloudFront configuration that ties an origin to a cache behaviour and gives you a public domain like d111111abcdef8.cloudfront.net.
Console steps:
- Open the AWS Management Console and go to CloudFront.
- Choose Create distribution.
- Under Origin domain, pick your S3 bucket or enter your ALB/server hostname.
- Set Viewer protocol policy to Redirect HTTP to HTTPS.
- Choose a cache policy, CachingOptimized is a good default for static content.
- (Optional) Add your custom domain under Alternate domain names (CNAME) and attach an ACM certificate.
- Choose Create distribution and wait for Status: Enabled (a few minutes).
AWS CLI (v2): the full distribution config is large, so it is usually passed as a JSON file.
aws cloudfront create-distribution \
--distribution-config file://distribution-config.json
Output:
{
"Distribution": {
"Id": "E1A2B3C4D5E6F7",
"DomainName": "d111111abcdef8.cloudfront.net",
"Status": "InProgress"
}
}
A deeper, end-to-end walkthrough lives in Create a CloudFront distribution.
The stale-cache trap after a deploy
This is the single most common CloudFront surprise. You deploy new code, refresh the page, and nothing changes, the old version keeps loading. The reason: that file is still sitting in edge caches around the world, and CloudFront will keep serving it until its TTL (Time To Live, how long a cached copy is considered fresh) expires.
There are two reliable fixes:
Option 1, invalidate the cache. An invalidation tells CloudFront to throw out cached copies of matching paths so the next request re-fetches from origin.
aws cloudfront create-invalidation \
--distribution-id E1A2B3C4D5E6F7 \
--paths "/*"
Output:
{
"Invalidation": {
"Id": "I2J3K4L5M6N7O8",
"Status": "InProgress"
}
}
Option 2 (preferred), use versioned filenames. Instead of overwriting app.js, ship app.a1b2c3.js with a content hash in the name. Every deploy produces new filenames, so the browser and edge naturally fetch the new files and never serve stale ones. Modern build tools (Vite, webpack) do this automatically.
Cost tip: The first 1,000 invalidation paths per month are free, then it is about $0.005 per path. Invalidating
"/*"counts as one path, so it is cheap for occasional deploys, but versioned filenames are still better because they avoid invalidations entirely and never serve stale content even for a moment.
Cost note
CloudFront has a generous free tier (as of 2026, 1 TB of data transfer out and 10 million requests per month, free). Beyond that, data transfer to the internet is roughly $0.085 per GB in North America and Europe, with HTTPS requests around $0.01 per 10,000. For most small sites the bill stays within the free tier, and serving from CloudFront can even be cheaper than serving directly from S3 or an ALB because edge cache hits avoid origin transfer costs.
Best practices
- Cache aggressively for static assets and use versioned filenames so you rarely need invalidations.
- Set Viewer protocol policy to redirect HTTP to HTTPS, and attach a free ACM certificate for your custom domain.
- Use the managed CachingOptimized policy for static content and CachingDisabled for truly dynamic paths, rather than caching everything.
- Forward only the cookies, headers, and query strings your origin actually needs, every extra varied value lowers your cache hit rate.
- Keep the origin private (e.g. S3 with Origin Access Control) so users can only reach it through CloudFront.
- Monitor the cache hit ratio in the CloudFront console, a low ratio usually means your content is not as cacheable as you thought.