Lambda@Edge vs CloudFront Functions
31 Dec 2025Both run your code at CloudFront’s edge locations. They are not interchangeable, and picking the expensive one for a job the cheap one handles is the most common mistake here.
The actual difference
| CloudFront Functions | Lambda@Edge | |
|---|---|---|
| Runtime | JavaScript (limited subset) | Node.js or Python, full runtime |
| Execution locations | 600+ edge locations | Fewer, regional edge caches |
| Max execution time | Sub-millisecond, hard cap | Up to 5s (viewer), 30s (origin) |
| Can call other AWS services | No | Yes |
| Can modify request body | No | Yes (origin-facing events only) |
| Trigger points | Viewer request/response only | Viewer and origin request/response |
| Cost | Fraction of Lambda@Edge, per invocation | Meaningfully higher per invocation |
| Cold starts | None | Possible, especially at low traffic |
When CloudFront Functions is the right call
Anything that’s pure, fast, synchronous logic on the request or response with no external calls:
function handler(event) {
var request = event.request;
var uri = request.uri;
// redirect /old-path to /new-path
if (uri === '/old-path') {
return {
statusCode: 301,
statusDescription: 'Moved',
headers: { location: { value: '/new-path' } },
};
}
// add a security header
return request;
}
- URL rewrites and redirects
- Adding/stripping request or response headers (security headers, CORS)
- Simple A/B test routing by cookie value
- Normalizing query strings or paths for better cache hit rates
If your logic fits in a function with no await, no network call, no AWS SDK — this is almost always the right tool, and it’s dramatically cheaper at any real volume.
When you actually need Lambda@Edge
Anything requiring a real runtime or an external call:
- Auth that checks a token against DynamoDB or calls out to an identity provider — needs the AWS SDK and network access, which CloudFront Functions doesn’t have.
- Image resizing or format negotiation at the origin-request stage — needs real compute and libraries.
- Modifying the origin request body, or logic that genuinely needs Node’s ecosystem (npm packages, complex parsing).
- Anything at the origin-response stage that needs to enrich the response using data pulled from elsewhere.
exports.handler = async (event) => {
const request = event.Records[0].cf.request
const authHeader = request.headers.authorization?.[0]?.value
const isValid = await verifyTokenAgainstService(authHeader)
if (!isValid) {
return { status: '403', statusDescription: 'Forbidden' }
}
return request
}
The mistake to avoid
Reaching for Lambda@Edge by default because it’s more familiar (it’s “just Lambda”) when the actual logic is a header rewrite or a redirect. That decision costs you on every single request at every edge location, permanently, for something CloudFront Functions does for a fraction of the price with lower latency and no cold starts. Default to CloudFront Functions and only escalate to Lambda@Edge when you hit something it genuinely can’t do — an external call, a real runtime dependency, or execution time past its cap.
Gotcha
Lambda@Edge functions deployed for CloudFront must be created in us-east-1, regardless of where your distribution or your other infrastructure lives — deploy it in any other region and CloudFront simply won’t let you associate it. This trips people up constantly because it’s not documented prominently in the console flow, only in the fine print.