Loading learning content...
When Amazon Web Services launched CloudFront in 2008, it wasn't just adding a CDN to its portfolio—it was recognizing a fundamental truth about modern application architecture: content delivery cannot be separated from application infrastructure.
Today, AWS CloudFront is the most deeply integrated CDN in the cloud ecosystem. It's not the largest (Akamai), not the most developer-friendly (Cloudflare), and not the fastest purging (Fastly). But for organizations running on AWS—which represents an estimated 32% of all cloud infrastructure spending—CloudFront offers something competitors cannot match: seamless, native integration with the entire AWS stack.
This page explores CloudFront's architecture, its unique Lambda@Edge computing capabilities, integration patterns with AWS services, and when the ecosystem advantage outweighs standalone CDN considerations.
By the end of this page, you will understand CloudFront's architecture and edge locations, Lambda@Edge and CloudFront Functions computing models, deep integration patterns with S3, ALB, API Gateway, and other AWS services, security configurations with AWS Shield and WAF, and when CloudFront is the optimal choice despite pure CDN feature gaps.
CloudFront operates a global network of edge locations and regional edge caches, designed to integrate seamlessly with AWS origins while supporting external origins.
Network Scale:
CloudFront Request Flow:
┌──────────────────────────────────────────────────────────────────────────────┐
│ CloudFront Request Processing Flow │
├──────────────────────────────────────────────────────────────────────────────┤
│ │
│ Client Request │
│ │ │
│ │ DNS Resolution: d123.cloudfront.net │
│ ▼ │
│ ┌───────────────────────┐ │
│ │ Route 53 / DNS │ → Anycast to nearest edge location │
│ └───────────┬───────────┘ │
│ │ │
│ ▼ │
│ ┌───────────────────────────────────────────────────────────────────┐ │
│ │ Edge Location (POP) │ │
│ │ ┌─────────────────┐ ┌─────────────────┐ ┌───────────────────┐ │ │
│ │ │ SSL Termination │→ │ CloudFront Func │→ │ Cache Check │ │ │
│ │ │ │ │ (Viewer Request)│ │ │ │ │
│ │ └─────────────────┘ └─────────────────┘ └─────────┬─────────┘ │ │
│ │ │ │ │
│ │ Cache Hit ←───────────────┘ │ │
│ │ │ │ │
│ │ ▼ Cache Miss │ │
│ │ ┌──────────────┐ │ │ │
│ │ │ Serve │ │ │ │
│ │ │ Response │ ▼ │ │
│ │ └──────────────┘ ┌───────────────────┐ │ │
│ │ │ Lambda@Edge │ │ │
│ │ │ (Origin Request) │ │ │
│ │ └─────────┬─────────┘ │ │
│ └──────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌───────────────────────────────────────────────────────────────────┐ │
│ │ Regional Edge Cache (if applicable) │ │
│ │ Aggregates requests across multiple POPs │ │
│ └───────────────────────────────────┬───────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌───────────────────────────────────────────────────────────────────┐ │
│ │ Origin Server │ │
│ │ ┌─────────┐ ┌─────────┐ ┌─────────────┐ ┌───────────────┐ │ │
│ │ │ S3 │ │ ALB/NLB │ │ API Gateway │ │ Custom Origin │ │ │
│ │ │ Bucket │ │ │ │ │ │ (Any HTTP) │ │ │
│ │ └─────────┘ └─────────┘ └─────────────┘ └───────────────┘ │ │
│ └───────────────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────────────────┘
CloudFront's Regional Edge Caches serve a similar purpose to Cloudflare's paid Argo Tiered Caching or Fastly's Shield. However, CloudFront also offers explicit Origin Shield as an additional layer—a dedicated regional cache that further reduces origin load. Use Origin Shield for origins with limited capacity or high origin-fetch costs.
CloudFront's defining advantage is seamless integration with virtually every AWS service. These integrations often reduce complexity and cost compared to using third-party CDNs with AWS infrastructure.
Amazon S3 Integration:
The most common CloudFront pattern is serving static content from S3:
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
# CloudFormation template for CloudFront + S3 static siteAWSTemplateFormatVersion: '2010-09-09'Description: CloudFront distribution with S3 origin Resources: # S3 Bucket - Private, no public access needed ContentBucket: Type: AWS::S3::Bucket Properties: BucketName: my-static-content-bucket PublicAccessBlockConfiguration: BlockPublicAcls: true BlockPublicPolicy: true IgnorePublicAcls: true RestrictPublicBuckets: true # Origin Access Control - Secure S3 access CloudFrontOAC: Type: AWS::CloudFront::OriginAccessControl Properties: OriginAccessControlConfig: Name: S3-OAC OriginAccessControlOriginType: s3 SigningBehavior: always SigningProtocol: sigv4 # CloudFront Distribution Distribution: Type: AWS::CloudFront::Distribution Properties: DistributionConfig: Origins: - Id: S3Origin DomainName: !GetAtt ContentBucket.RegionalDomainName S3OriginConfig: OriginAccessIdentity: '' OriginAccessControlId: !GetAtt CloudFrontOAC.Id DefaultCacheBehavior: TargetOriginId: S3Origin ViewerProtocolPolicy: redirect-to-https CachePolicyId: !Ref CachePolicy # Enable compression Compress: true # Custom error responses for SPA CustomErrorResponses: - ErrorCode: 404 ResponseCode: 200 ResponsePagePath: /index.html - ErrorCode: 403 ResponseCode: 200 ResponsePagePath: /index.html Enabled: true HttpVersion: http2and3 DefaultRootObject: index.html # Cache Policy for optimal static content CachePolicy: Type: AWS::CloudFront::CachePolicy Properties: CachePolicyConfig: Name: StaticContentCachePolicy DefaultTTL: 86400 # 24 hours MaxTTL: 31536000 # 1 year MinTTL: 60 ParametersInCacheKeyAndForwardedToOrigin: EnableAcceptEncodingGzip: true EnableAcceptEncodingBrotli: true CookiesConfig: CookieBehavior: none HeadersConfig: HeaderBehavior: none QueryStringsConfig: QueryStringBehavior: noneKey S3 Integration Benefits:
Application Load Balancer (ALB) Integration:
For dynamic applications running on EC2, ECS, or EKS:
| Consideration | Recommendation | Rationale |
|---|---|---|
| Origin Protocol | HTTPS only | Encrypt traffic between CloudFront and ALB |
| ALB Security Groups | Allow only CloudFront IPs | Use AWS-managed prefix list (com.amazonaws.global.cloudfront.origin-facing) |
| Origin Shield | Enable for high-traffic APIs | Reduce ALB load by aggregating cache misses |
| Cache Policy | Use CachingDisabled for dynamic | Forward all headers/cookies for session-based apps |
| Connection Keepalive | Enable persistent connections | Reduce TLS handshake overhead to origin |
API Gateway Integration:
CloudFront in front of API Gateway provides:
Data transfer from AWS origins (S3, ALB, API Gateway) to CloudFront is free. You only pay for CloudFront to viewer transfer. This is a significant cost advantage over third-party CDNs, which would incur both origin egress and CDN ingress costs.
Lambda@Edge extends AWS Lambda to CloudFront's edge locations, enabling sophisticated request and response manipulation at the network edge.
Lambda@Edge Execution Points:
Lambda@Edge functions can execute at four points in the request lifecycle:
┌────────────────────────────────────────────────────────────────────────────────┐
│ Lambda@Edge Execution Points │
├────────────────────────────────────────────────────────────────────────────────┤
│ │
│ Client │
│ │ │
│ │ ① │
│ ▼ │
│ ┌────────────────────────────────────────────────────────────────────────┐ │
│ │ VIEWER REQUEST │ │
│ │ • Executes for every request │ │
│ │ • Before cache check │ │
│ │ • Use cases: Auth, geo-redirect, URL rewrite │ │
│ │ • Limits: 5s timeout, 128MB memory, 1MB body │ │
│ └───────────────────────────────────┬────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────┐ │
│ │ Cache Check │ │
│ └─────────┬───────────┘ │
│ │ │
│ Cache Hit ◄──────┴──────► Cache Miss │
│ │ │ │
│ │ ② │ │
│ │ ▼ │
│ │ ┌────────────────────────────────────────────────┐│
│ │ │ ORIGIN REQUEST ││
│ │ │ • Executes only on cache miss ││
│ │ │ • Before origin fetch ││
│ │ │ • Use cases: Origin selection, header manip ││
│ │ │ • Limits: 30s timeout, 128MB memory ││
│ │ └───────────────────────────────────────────────┘│
│ │ │ │
│ │ ▼ │
│ │ ┌─────────┐ │
│ │ │ Origin │ │
│ │ └────┬────┘ │
│ │ │ │
│ │ ③ │ │
│ │ ▼ │
│ │ ┌────────────────────────────────────────────────┐│
│ │ │ ORIGIN RESPONSE ││
│ │ │ • Executes after origin returns ││
│ │ │ • Before caching ││
│ │ │ • Use cases: Response modification, headers ││
│ │ │ • Limits: 30s timeout, 128MB memory ││
│ │ └───────────────────────────────────────────────┘│
│ │ │ │
│ └────────────┬────────────┘ │
│ ▼ │
│ ④ │
│ ┌────────────────────────────────────────────────────────────────────────┐ │
│ │ VIEWER RESPONSE │ │
│ │ • Executes for every response │ │
│ │ • Before sending to client │ │
│ │ • Use cases: Security headers, compression, CORS │ │
│ │ • Limits: 5s timeout, 128MB memory │ │
│ └───────────────────────────────────┬────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ Client │
└────────────────────────────────────────────────────────────────────────────────┘
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748
/** * Lambda@Edge: Viewer Request - JWT Authentication * Validate JWT tokens before requests reach origin */const jwt = require('jsonwebtoken'); // Note: Must bundle secrets - cannot use environment variablesconst JWT_SECRET = 'your-secret-key'; // In practice, use SSM or hardcoded during build exports.handler = async (event) => { const request = event.Records[0].cf.request; const headers = request.headers; // Extract token from Authorization header const authHeader = headers['authorization']; if (!authHeader || !authHeader[0]) { return { status: '401', statusDescription: 'Unauthorized', headers: { 'content-type': [{ key: 'Content-Type', value: 'application/json' }], }, body: JSON.stringify({ error: 'Missing authorization header' }), }; } const token = authHeader[0].value.replace('Bearer ', ''); try { const decoded = jwt.verify(token, JWT_SECRET); // Add user info to headers for origin request.headers['x-user-id'] = [{ key: 'X-User-Id', value: decoded.sub }]; request.headers['x-user-role'] = [{ key: 'X-User-Role', value: decoded.role }]; return request; } catch (error) { return { status: '401', statusDescription: 'Unauthorized', headers: { 'content-type': [{ key: 'Content-Type', value: 'application/json' }], }, body: JSON.stringify({ error: 'Invalid token' }), }; }};Lambda@Edge functions must be deployed in us-east-1 and are replicated globally. They cannot access VPC resources, have limited memory (128MB), and cannot use environment variables. Cold starts are slower than Cloudflare Workers (100-200ms vs <5ms). Consider CloudFront Functions for simpler use cases.
CloudFront Functions provide a lighter-weight alternative to Lambda@Edge for simple request/response manipulations, with significantly better performance characteristics.
CloudFront Functions vs Lambda@Edge:
| Characteristic | CloudFront Functions | Lambda@Edge |
|---|---|---|
| Execution Points | Viewer request/response only | All four points |
| Runtime | JavaScript (ECMAScript 5.1) | Node.js or Python |
| Execution Time Limit | 1 ms | 5-30 seconds |
| Memory | 2 MB | 128-10,240 MB |
| Package Size | 10 KB | 1-50 MB |
| Network Access | None | Full internet access |
| Cold Start | Sub-millisecond | 100-200+ ms |
| Price | $0.10/million invocations | $0.60/million + duration |
| Scale | 10M+ requests/second | 10K requests/second per region |
1234567891011121314151617181920212223242526
/** * CloudFront Function: Viewer Request - URL Rewriting * Rewrite clean URLs to actual file paths */function handler(event) { var request = event.request; var uri = request.uri; // Handle SPA routing - serve index.html for paths without extensions if (!uri.includes('.')) { // Check if path ends with / or has no extension if (uri.endsWith('/')) { request.uri = uri + 'index.html'; } else if (!uri.split('/').pop().includes('.')) { request.uri = '/index.html'; } } // Add file extension for API versioning // /api/v2/users -> /api/v2/users.json if (uri.startsWith('/api/') && !uri.includes('.')) { request.uri = uri + '.json'; } return request;}Use CloudFront Functions for: URL rewrites, header manipulation, simple redirects, cache key normalization. Use Lambda@Edge for: authentication with external validation, complex routing logic, response body transformation, anything requiring network calls or more than 1ms execution time.
CloudFront's security is deeply integrated with AWS's security services, providing layered protection from network to application level.
AWS Shield Integration:
All CloudFront distributions automatically receive AWS Shield Standard protection—free, always-on DDoS defense:
AWS Shield Advanced (paid, starting ~$3,000/month) adds:
AWS WAF Integration:
AWS WAF provides web application firewall capabilities directly at the CloudFront edge:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
# AWS WAF Web ACL for CloudFrontresource "aws_wafv2_web_acl" "cloudfront_waf" { name = "cloudfront-protection" description = "WAF rules for CloudFront distribution" scope = "CLOUDFRONT" # Must be CLOUDFRONT for CF distributions default_action { allow {} } # AWS Managed Rules - Core Rule Set rule { name = "AWSManagedRulesCommonRuleSet" priority = 1 override_action { none {} # Use rule actions as-is } statement { managed_rule_group_statement { name = "AWSManagedRulesCommonRuleSet" vendor_name = "AWS" # Exclude rules that cause false positives excluded_rule { name = "SizeRestrictions_BODY" } } } visibility_config { sampled_requests_enabled = true cloudwatch_metrics_enabled = true metric_name = "CommonRuleSetMetric" } } # AWS Managed Rules - Known Bad Inputs rule { name = "AWSManagedRulesKnownBadInputsRuleSet" priority = 2 override_action { none {} } statement { managed_rule_group_statement { name = "AWSManagedRulesKnownBadInputsRuleSet" vendor_name = "AWS" } } visibility_config { sampled_requests_enabled = true cloudwatch_metrics_enabled = true metric_name = "BadInputsMetric" } } # Rate limiting rule rule { name = "RateLimitRule" priority = 3 action { block {} } statement { rate_based_statement { limit = 2000 # requests per 5 minutes aggregate_key_type = "IP" scope_down_statement { # Only rate limit login endpoint byte_match_statement { search_string = "/api/auth/login" field_to_match { uri_path {} } positional_constraint = "STARTS_WITH" text_transformation { priority = 0 type = "LOWERCASE" } } } } } visibility_config { sampled_requests_enabled = true cloudwatch_metrics_enabled = true metric_name = "RateLimitMetric" } } # Geo-blocking rule rule { name = "GeoBlockRule" priority = 4 action { block {} } statement { geo_match_statement { country_codes = ["RU", "CN", "KP"] # Block specific countries } } visibility_config { sampled_requests_enabled = true cloudwatch_metrics_enabled = true metric_name = "GeoBlockMetric" } } visibility_config { cloudwatch_metrics_enabled = true metric_name = "CloudFrontWAF" sampled_requests_enabled = true }} # Associate WAF with CloudFront distributionresource "aws_cloudfront_distribution" "cdn" { # ... other config ... web_acl_id = aws_wafv2_web_acl.cloudfront_waf.arn}AWS WAF charges $5/month per web ACL + $1/month per rule + $0.60 per million requests. Managed rule groups add $1-10/month per group. For high-traffic sites, request charges dominate. Bot Control adds $10/month + $1/million requests. Always enable sampled request logging to CloudWatch for debugging.
CloudFront's caching behavior is highly configurable through cache policies and origin request policies, enabling fine-grained control over what gets cached and what gets forwarded to origin.
Cache Policies:
Cache policies determine what's included in the cache key and TTL settings:
| Policy Name | Use Case | Key Characteristics |
|---|---|---|
| CachingOptimized | Static content | Long TTLs, no headers/cookies/query strings in key |
| CachingOptimizedForUncompressedObjects | Pre-compressed content | Like above, but doesn't normalize Accept-Encoding |
| CachingDisabled | Dynamic content | No caching, all requests to origin |
| Elemental-MediaPackage | Video streaming | Optimized for HLS/DASH manifest and segment caching |
| Amplify | Amplify Hosting | Configured for Amplify's caching patterns |
Origin Request Policies:
Separate from cache policies, origin request policies control what CloudFront forwards to your origin when it needs to fetch content:
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
# Custom cache policy for API responsesresource "aws_cloudfront_cache_policy" "api_cache" { name = "API-Caching-Policy" comment = "Cache API responses based on auth and accept headers" default_ttl = 300 # 5 minutes default max_ttl = 3600 # 1 hour max min_ttl = 0 # Respect Cache-Control: no-cache parameters_in_cache_key_and_forwarded_to_origin { # Include compression headers in cache key enable_accept_encoding_brotli = true enable_accept_encoding_gzip = true # Include specific headers in cache key headers_config { header_behavior = "whitelist" headers { items = [ "Authorization", # Different cache per user "Accept-Language", # Language-specific responses "CloudFront-Viewer-Country" # Country-specific content ] } } # Include cookies in cache key cookies_config { cookie_behavior = "whitelist" cookies { items = ["session_id", "user_preferences"] } } # Include query strings in cache key query_strings_config { query_string_behavior = "whitelist" query_strings { items = ["page", "limit", "sort", "filter"] } } }} # Origin request policy - forward additional headersresource "aws_cloudfront_origin_request_policy" "api_origin" { name = "API-Origin-Policy" comment = "Forward necessary headers to API origin" headers_config { header_behavior = "whitelist" headers { items = [ "Authorization", "Origin", "Access-Control-Request-Method", "Access-Control-Request-Headers", "X-Request-ID" ] } } cookies_config { cookie_behavior = "all" # Forward all cookies to origin } query_strings_config { query_string_behavior = "all" # Forward all query strings }} # Apply policies to cache behaviorresource "aws_cloudfront_distribution" "api" { # ... origin config ... default_cache_behavior { target_origin_id = "api-origin" viewer_protocol_policy = "https-only" allowed_methods = ["DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT"] cached_methods = ["GET", "HEAD"] cache_policy_id = aws_cloudfront_cache_policy.api_cache.id origin_request_policy_id = aws_cloudfront_origin_request_policy.api_origin.id compress = true }}The cache key determines cache hit ratio. Include too little (e.g., ignore Authorization header) and you'll serve cached private data to wrong users. Include too much (e.g., all headers) and every request becomes a cache miss. Start with managed policies and customize only when needed.
CloudFront uses consumption-based pricing with regional variation. Understanding the cost structure is essential for budgeting and optimization.
Pricing Components:
| Component | Price Range | Notes |
|---|---|---|
| Data Transfer Out (first 10TB) | $0.085/GB | Decreases with volume |
| Data Transfer Out (10-50TB) | $0.080/GB | Volume tier pricing |
| Data Transfer Out (50-150TB) | $0.060/GB | Volume tier pricing |
| HTTP/HTTPS Requests | $0.0075-0.01/10K | Varies by protocol and region |
| Origin Shield Requests | $0.0090/10K | Additional for cache aggregation |
| Lambda@Edge Invocations | $0.60/million | Plus duration-based compute |
| CloudFront Functions | $0.10/million | Significantly cheaper than L@E |
| Field-Level Encryption | $0.02/10K requests | For encrypting specific fields |
Cost Optimization Strategies:
CloudFront's free tier includes 1TB data transfer out and 10 million HTTP/HTTPS requests per month for the first 12 months. This covers most startup needs during early development and testing phases.
CloudFront's value proposition centers on AWS integration. Use this framework to evaluate fit:
You now understand AWS CloudFront's architecture, deep AWS integration advantages, edge computing capabilities with Lambda@Edge and CloudFront Functions, security integration, and when the AWS ecosystem value outweighs standalone CDN features. Next, we'll explore Fastly's real-time purge capabilities and developer-centric approach.