This chapter covers AWS CloudFront Functions, a serverless edge computing feature that allows you to run lightweight JavaScript code at CloudFront edge locations for request and response manipulation. Understanding CloudFront Functions is essential for the SAA-C03 exam, as it tests your ability to optimize content delivery and reduce latency for global applications. Approximately 5-10% of exam questions in the High Performance domain involve edge computing choices, including distinguishing CloudFront Functions from Lambda@Edge.
Jump to a section
Imagine a massive highway system with multiple toll plazas at the entrance to a major city. Each toll booth has a fast lane (Express Lane) and a standard lane. The Express Lane uses an automated system that reads your license plate and charges your pre-paid account instantly without stopping. The standard lane uses a human operator who takes cash, gives change, and may ask for directions. The Express Lane operates at the speed of the vehicle passing under a sensor, processing in microseconds, and is limited to simple transactions like deducting a fixed toll. The standard lane can handle complex tasks like issuing receipts, providing maps, and answering questions, but takes seconds per vehicle. In this analogy, CloudFront Functions are the Express Lane toll booths: they execute at the edge with ultra-low latency (submillisecond) for simple HTTP request/response transformations (like URL rewrites, header manipulation, authentication redirects). Lambda@Edge is the standard lane: it can run more complex code with dependencies, access external services, and has longer execution time limits. CloudFront Functions are ideal for high-volume, latency-sensitive operations where only simple logic is needed, while Lambda@Edge handles heavyweight processing that can tolerate higher latency. Choosing between them depends on whether your use case fits in the Express Lane's constraints or requires the full flexibility of the standard lane.
What is CloudFront Functions?
CloudFront Functions is a feature of Amazon CloudFront that lets you write lightweight JavaScript functions to manipulate HTTP requests and responses at the edge. These functions execute at CloudFront edge locations, which are the points of presence (PoPs) closest to your viewers. The primary purpose is to perform simple, high-frequency operations such as URL rewrites, header manipulation, cache key normalization, and authentication redirects with extremely low latency.
Why CloudFront Functions Exists
Before CloudFront Functions, the only way to run custom logic at the edge was Lambda@Edge, which is a full Lambda function triggered by CloudFront events. However, Lambda@Edge has higher latency (on the order of milliseconds) due to function cold starts and execution overhead. For use cases that require submillisecond processing, such as modifying every request to a high-traffic website, Lambda@Edge can be too slow. CloudFront Functions fills this gap by providing a lightweight runtime optimized for speed.
How CloudFront Functions Work Internally
CloudFront Functions are written in JavaScript (ECMAScript 5.1 compliant) and use a custom runtime that is heavily optimized for low latency. The runtime does not support Node.js APIs; instead, it provides a minimal set of built-in objects and methods. Functions are triggered by two CloudFront events: viewer request and viewer response. They execute before CloudFront checks its cache for viewer request events and after CloudFront receives the response from the origin for viewer response events.
At a high level, the flow is: 1. A viewer sends an HTTP request to a CloudFront distribution. 2. CloudFront receives the request at an edge location. 3. If a viewer request function is associated, CloudFront invokes it with the request object. 4. The function runs and returns a modified request object or generates a response (e.g., redirect or 401). 5. CloudFront then checks its cache using the (possibly modified) request. 6. If a cache miss occurs, CloudFront forwards the request to the origin. 7. When the origin responds, if a viewer response function is associated, CloudFront invokes it with the response object. 8. The function modifies the response (e.g., adding headers) and returns it. 9. CloudFront caches the response (if appropriate) and sends it to the viewer.
Key implementation details:
Functions run in a sandboxed environment with no access to the network or filesystem.
Memory limit: 2 MB per function.
Execution time limit: 5 seconds for viewer request, 10 seconds for viewer response (though typical execution is under 1 ms).
Function code size limit: 10 KB.
Response body size limit: 1 MB (for generated responses).
Only synchronous JavaScript is supported; no async/await or callbacks.
Built-in objects include: Math, JSON, String, Array, Object, Date, RegExp, console (limited), atob, btoa, crypto (limited), URL, URLSearchParams, TextEncoder, TextDecoder.
The request and response objects are simplified versions of the standard HTTP request/response, with properties like uri, method, headers, querystring, cookies.
Defaults and Limits
Maximum number of functions per distribution: 10.
Maximum number of function associations per distribution: 10.
Function code size: 10 KB max.
Function memory: 2 MB max.
Execution time: 5 seconds (viewer request), 10 seconds (viewer response).
Response body size (if function generates response): 1 MB max.
Supported regions: All CloudFront edge locations globally.
Pricing: $0.10 per 1 million invocations (first 10 million free per month) plus $0.15 per 1 million compute time in GB-second (first 2 million GB-second free).
Configuration and Verification
To create a CloudFront Function, you can use the AWS Management Console, AWS CLI, or AWS SDK. The steps are:
Write the JavaScript function code.
Create a function in CloudFront (console or CLI).
Publish a version of the function.
Associate the function with a CloudFront distribution's cache behavior for viewer request or viewer response events.
Example CLI command to create a function:
aws cloudfront create-function --name my-function --function-config Comment="My function",Runtime=cloudfront-js-1.0 --function-code file://function.jsExample function code (URL rewrite):
function handler(event) {
var request = event.request;
var uri = request.uri;
// Rewrite /old-path/* to /new-path/*
if (uri.startsWith('/old-path/')) {
request.uri = uri.replace('/old-path/', '/new-path/');
}
return request;
}To test a function, you can use the CloudFront console's test tab, which simulates a request and shows the function's output.
Interaction with Related Technologies
CloudFront Functions complement Lambda@Edge. For more complex processing (e.g., database access, external API calls, image manipulation, or functions requiring Node.js modules), you must use Lambda@Edge. Lambda@Edge supports longer execution times (up to 30 seconds), larger function size (50 MB compressed), and a full Node.js or Python runtime. However, Lambda@Edge incurs higher latency (cold starts) and higher cost per invocation.
CloudFront Functions also interact with CloudFront's caching behavior. Since viewer request functions execute before cache lookup, they can modify the cache key (e.g., by normalizing query strings or rewriting URLs). This can improve cache hit ratios. Viewer response functions can modify responses before caching, but changes to the response body are not supported (only headers, status code, and cookies).
Use Cases
URL redirects and rewrites (e.g., redirecting HTTP to HTTPS, rewriting /index.html to /).
Header manipulation (e.g., adding security headers like X-Frame-Options, Content-Security-Policy).
Cache key normalization (e.g., removing tracking query parameters, sorting query parameters).
A/B testing by setting cookies or headers.
Authentication and authorization checks (e.g., checking for a valid token in a cookie).
Geolocation-based content serving (using CloudFront's CloudFront-Viewer-Country header).
Request filtering based on headers or IP addresses.
Performance Characteristics
CloudFront Functions are designed for submillisecond execution. In benchmarks, typical functions execute in 0.5-2 ms. This is orders of magnitude faster than Lambda@Edge, which often takes 5-50 ms due to cold starts and runtime overhead. For high-traffic sites with millions of requests per minute, this latency difference is critical.
Limitations
No access to external resources (network, file system).
No support for Node.js modules (only pure JavaScript).
Limited runtime capabilities (no async/await, limited built-in objects).
Function code size limited to 10 KB.
Response body modification only allowed when the function generates a new response (not when modifying an origin response).
Cannot modify viewer request after origin response (only viewer response can modify).
Best Practices
Keep functions simple and focused on a single task.
Minimize memory usage by avoiding large objects.
Use early returns to reduce execution time.
For complex logic, consider Lambda@Edge instead.
Test functions thoroughly with the CloudFront console test tool.
Monitor function invocations and errors using CloudWatch metrics (provided automatically).
Create the JavaScript Function Code
Write your JavaScript code in a file (e.g., function.js). The code must define a handler function that receives an event object with a request or response property. For viewer request, you return the modified request or a new response. For viewer response, you return the modified response. The code must be self-contained with no external dependencies. Example: a function that redirects all requests to HTTPS by checking the 'cloudfront-forwarded-proto' header and returning a 301 response if the protocol is HTTP.
Create the CloudFront Function
Use the AWS CloudFront console, CLI, or SDK to create the function. In the console, navigate to 'Functions' under CloudFront, click 'Create function', and paste your code. Provide a name and optional comment. The runtime is fixed at 'cloudfront-js-1.0'. The function is created in a 'DEVELOPMENT' stage. You can test it immediately using the built-in test tool with sample events.
Publish a Function Version
After testing, publish a version of the function. This creates an immutable snapshot. In the console, click 'Publish'. You can have multiple versions, but only published versions can be associated with a distribution. The version number increments automatically. You can also use the CLI: `aws cloudfront publish-function --name my-function --if-match <ETag>`.
Associate Function with CloudFront Distribution
Associate the published function with a CloudFront distribution's cache behavior. In the console, go to your distribution, select the behavior (e.g., Default (*)), and under 'Function associations', choose the event type (Viewer Request or Viewer Response) and select the function and version. You can associate up to 2 functions per behavior (one viewer request, one viewer response). Save changes. The distribution will update (may take a few minutes).
Test and Monitor the Function
After association, test by sending requests to your CloudFront domain. Check if the function behaves as expected (e.g., redirects, header modifications). Monitor using CloudWatch metrics: `FunctionInvocations`, `FunctionErrors`, `FunctionExecutionTime`. You can also enable logging in CloudFront to see request details. If errors occur, check the function code for syntax errors or logic issues. Use the console test tool to debug.
Enterprise Scenario 1: Global E-commerce Platform
A large e-commerce company serves millions of users worldwide. They need to redirect users to localized content based on their country. Using CloudFront Functions, they write a viewer request function that reads the CloudFront-Viewer-Country header, maps it to a country code, and rewrites the URL prefix (e.g., /us/ to /de/ for German users). This function executes in under 1 ms, ensuring no noticeable delay. Previously, they used Lambda@Edge, which added 20-50 ms latency per request, impacting conversion rates. The function is associated with the default cache behavior. They also normalize query strings by removing tracking parameters (e.g., utm_source) to improve cache hit ratios. The function code is under 2 KB and handles 50,000 requests per second during peak. They monitor FunctionExecutionTime and keep it below 0.8 ms. A common misconfiguration is forgetting to handle missing headers, causing errors; they added a default country fallback.
Enterprise Scenario 2: Media Streaming Service
A video streaming service uses CloudFront to deliver content. They need to add security headers like X-Content-Type-Options and Strict-Transport-Security to all responses. They use a viewer response function to add these headers. The function also sets a Set-Cookie header for a session token if the request includes a valid token in the query string. The function runs at the edge, reducing origin load. They handle 100,000 requests per minute. The function is tested with the console tool and deployed across multiple distributions. A pitfall is that viewer response functions cannot modify the response body; they attempted to add a watermark but had to use Lambda@Edge instead.
Enterprise Scenario 3: SaaS Provider with Multi-Tenant Application
A SaaS company hosts customer-specific applications behind CloudFront. They use a viewer request function to extract a tenant ID from the hostname or URL path and rewrite the request to the correct origin path. They also add a custom header X-Tenant-ID for the origin to identify the tenant. The function is lightweight and processes 10,000 requests per second. They use CloudFront Functions because Lambda@Edge would introduce unacceptable latency for their real-time application. They encountered an issue where the function code exceeded 10 KB after adding complex tenant mapping; they had to simplify the logic and use a lookup table with a smaller size. They also learned that functions cannot access external databases, so they preload mappings in the code.
What SAA-C03 Tests on CloudFront Functions
The SAA-C03 exam assesses your ability to choose between CloudFront Functions and Lambda@Edge for edge processing. The objective is 3.4: 'Design high-performing and reliable architectures' with a focus on content delivery and edge computing. You must understand the constraints, use cases, and performance characteristics of each.
Common Wrong Answers and Why Candidates Choose Them
'Use Lambda@Edge for all edge processing' — Candidates often assume Lambda@Edge is always better because it is more powerful. However, the exam tests cost and latency optimization. For simple, high-volume operations, CloudFront Functions are cheaper and faster. The exam will present a scenario with millions of requests per day and ask for the most cost-effective and low-latency solution. Choosing Lambda@Edge would be wrong.
'CloudFront Functions can access DynamoDB' — Some candidates think that because Lambda@Edge can access databases, CloudFront Functions can too. But CloudFront Functions have no network access. The exam may describe a need to look up user data; the correct answer is Lambda@Edge, not CloudFront Functions.
'CloudFront Functions can modify response bodies' — Candidates confuse viewer response with origin response. CloudFront Functions can only modify headers, status code, and cookies in viewer response; they cannot modify the body of the origin response. If the scenario requires body modification, Lambda@Edge is needed.
'CloudFront Functions support async/await' — The runtime is based on ECMAScript 5.1 and does not support async/await. Candidates who write modern JavaScript may assume it works, but the exam expects you to know this limitation.
Specific Numbers and Terms to Memorize
Execution time limit: 5 seconds (viewer request), 10 seconds (viewer response).
Function code size: 10 KB max.
Memory: 2 MB max.
Response body size (generated): 1 MB max.
Pricing: $0.10 per million invocations, $0.15 per GB-second compute.
Runtime: cloudfront-js-1.0.
Events: viewer request, viewer response.
Maximum functions per distribution: 10.
Edge Cases and Exceptions
If a function generates a response (e.g., redirect), CloudFront does not cache that response by default. You can set CloudFront-Response-Header to control caching.
Functions cannot access the request body. If you need to inspect or modify the body, use Lambda@Edge.
Functions are not available in all edge locations? Actually, they are available in all CloudFront edge locations globally.
You cannot use environment variables or layers.
The console.log output is sent to CloudWatch Logs only if you enable logging for the distribution.
How to Eliminate Wrong Answers
If the scenario mentions 'submillisecond latency' or 'high throughput' (e.g., millions of requests per second), lean toward CloudFront Functions.
If the scenario requires access to external services (DynamoDB, S3, external API), it must be Lambda@Edge.
If the function needs to modify the response body, it cannot be CloudFront Functions (use Lambda@Edge).
If the function code is larger than 10 KB, it must be Lambda@Edge.
If the scenario involves complex logic with async operations, choose Lambda@Edge.
Look for keywords: 'simple', 'lightweight', 'header manipulation', 'URL rewrite', 'cache key normalization' → CloudFront Functions. 'Complex', 'business logic', 'database', 'external call' → Lambda@Edge.
CloudFront Functions are lightweight, submillisecond JavaScript functions that run at CloudFront edge locations for viewer request and viewer response events.
Maximum function code size is 10 KB; execution time limits are 5 seconds (viewer request) and 10 seconds (viewer response).
CloudFront Functions cannot access external resources (no network, no filesystem) and cannot modify response bodies from the origin.
Use CloudFront Functions for simple, high-volume operations like URL rewrites, header manipulation, cache key normalization, and authentication redirects.
For complex logic, database access, or longer execution times, use Lambda@Edge instead.
CloudFront Functions pricing is $0.10 per million invocations, significantly cheaper than Lambda@Edge for high-volume use cases.
Functions are created, tested, and published in the CloudFront console or CLI, then associated with a distribution's cache behavior.
The exam tests your ability to choose between CloudFront Functions and Lambda@Edge based on latency, complexity, and cost requirements.
Common wrong answers include using Lambda@Edge when CloudFront Functions suffice, or assuming CloudFront Functions can access DynamoDB.
Monitor function performance using CloudWatch metrics: FunctionInvocations, FunctionErrors, and FunctionExecutionTime.
These come up on the exam all the time. Here's how to tell them apart.
CloudFront Functions
Execution time up to 5 seconds (viewer request) or 10 seconds (viewer response)
Code size max 10 KB
Memory max 2 MB
No network access, no external dependencies
Only JavaScript (ECMAScript 5.1), no async/await
Lambda@Edge
Execution time up to 30 seconds (viewer request/response) or 5 minutes (origin request/response)
Code size max 50 MB (compressed) or 250 MB (uncompressed)
Memory up to 10,240 MB
Full network access, can call AWS services and external APIs
Supports Node.js, Python, and other runtimes with full async support
Mistake
CloudFront Functions can access the request body.
Correct
CloudFront Functions cannot access the request body. The event object does not contain a body property. If you need to inspect or modify the request body, you must use Lambda@Edge.
Mistake
CloudFront Functions can make HTTP requests to external APIs.
Correct
CloudFront Functions run in a sandboxed environment with no network access. They cannot make HTTP requests or access any external resources. For such needs, use Lambda@Edge.
Mistake
CloudFront Functions support Node.js modules like 'fs' or 'crypto'.
Correct
CloudFront Functions use a custom JavaScript runtime that does not include Node.js modules. Only built-in objects (e.g., Math, JSON, URL) are available. You cannot require or import any modules.
Mistake
CloudFront Functions can modify the response body from the origin.
Correct
CloudFront Functions in viewer response events can only modify headers, status code, and cookies. They cannot modify the response body. To modify the body, use Lambda@Edge origin response event.
Mistake
CloudFront Functions are more expensive than Lambda@Edge.
Correct
CloudFront Functions are significantly cheaper per invocation ($0.10 per million) compared to Lambda@Edge ($0.60 per million for the first 10 million). For high-volume simple operations, CloudFront Functions are more cost-effective.
Reveal each answer, then mark whether you got it right. Score 60%+ to unlock the next chapter.
CloudFront Functions are lightweight JavaScript functions with submillisecond execution times, limited to 10 KB code size and no network access. They are ideal for simple, high-volume edge processing like URL rewrites and header modifications. Lambda@Edge, on the other hand, supports multiple runtimes (Node.js, Python), can access external resources, has a higher execution time limit (up to 30 seconds), and is suitable for complex business logic. The exam expects you to choose based on latency requirements and functionality needs.
No, CloudFront Functions cannot access or modify the request body. The event object provided to the function does not include a body property. If you need to inspect or modify the request body, you must use Lambda@Edge with the origin request event. CloudFront Functions are designed for lightweight header and URL manipulation only.
Viewer request functions have a maximum execution time of 5 seconds. Viewer response functions have a maximum of 10 seconds. However, typical execution times are under 1 millisecond. These limits are generous, but the function will be terminated if it exceeds them. The exam may test these specific numbers, so memorize them.
You can test a CloudFront Function in the AWS Management Console using the built-in test tool. After creating the function, navigate to the 'Test' tab, provide a sample request event (you can use the default template or customize it), and click 'Test'. The function output will be displayed, showing the modified request or response. This allows you to verify logic before associating with a distribution.
Yes, CloudFront Functions can be used for A/B testing by modifying request headers or cookies to direct users to different versions of content. For example, you can set a cookie based on a percentage of users and rewrite the URL to point to a different origin path. However, keep in mind that the function must be simple and cannot access external databases for user segmentation.
If a CloudFront Function throws an error during execution, CloudFront returns a 502 Bad Gateway error to the viewer. The error is logged in CloudWatch Logs if logging is enabled for the distribution. You can monitor errors using the CloudWatch metric `FunctionErrors`. To debug, use the console test tool with sample events to identify and fix syntax or logic errors.
Yes, you can associate a CloudFront Function with up to 10 cache behaviors per distribution. Each behavior can have up to one viewer request function and one viewer response function. However, you can only associate up to 10 functions total per distribution. This allows you to apply different edge logic for different URL patterns.
You've just covered CloudFront Functions for Edge Logic — now see how well it sticks with free SAA-C03 practice questions. Full explanations included, no account needed.
Done with this chapter?