It depends on where the site lives. If it's on CloudFront, use them: it's the only reasonable way to do what every static host does for you, and it costs next to nothing. If it can live on Cloudflare, you don't need them at all.
This site is the example. It runs on a private S3 bucket behind CloudFront, and about 40 lines of JavaScript run on every page request before CloudFront fetches the file:
| Request | What the function does | Why |
|---|---|---|
www.cloudlesslabs.com/... |
Redirects to cloudlesslabs.com/... |
One domain for search engines |
ask.cloudlesslabs.com |
Serves /llms.txt; anything else there redirects to the main domain |
The map for AI assistants has its own address |
/stack |
Redirects to /stack/ |
One URL per page |
/stack/ |
Fetches stack/index.html |
A private bucket has no index page: without this, every page but the home page fails |
That's the right size for them: string work on the URL and the headers, in well under a millisecond. They can't call anything, read the request body or load a library, and that's the point: they start in no time and scale with CloudFront.
What I don't do is put logic there. Security headers belong in a response headers policy and error pages in the distribution's settings, both of them configuration, not code. Anything that needs the network or real work goes to the origin, or to a Cloudflare Worker in front.
Use it when
- A site on S3 and CloudFront: a private bucket behind origin access control has no index page, so /about/ must be rewritten to /about/index.html, or every page but the home page fails.
- Redirects at the edge: www to the apex, /about to /about/, old URLs to new ones, one subdomain served from a file of the same site.
- Headers and cache keys: add or strip headers, normalise query strings so the cache hits more often.
- A cheap check before the origin: a signed token, a basic-auth password on a staging site, a country rule.
Don't use it when
- Anything that needs the network, the request body, a library, or more than about a millisecond: it can't. Put the logic at the origin, in Lambda behind CloudFront, or in a Cloudflare Worker in front.
- A site you can host on Cloudflare: its static hosting does index pages, trailing slashes and redirect rules out of the box, with nothing to write.
- Settings that belong to the distribution: security headers go in a response headers policy, and error pages in custom error responses, not in code.
Pricing
$0.10 per million invocations, with 2 million a month free. Included in every CloudFront flat-rate plan. KeyValueStore reads $0.03 per million (2 million free), on the Pro plan and above.
Gotchas, with fixes
Gotcha: The runtime is a restricted JavaScript: no network, no file system, no environment variables, no timers, no request body, and the code is capped at 10 KB with 2 MB of memory.
Fix: Keep it to string work on the URL and headers. Values that change, such as a redirect table, go in KeyValueStore (runtime 2.0) rather than in the code.
Gotcha: A function runs on every request of the behaviour it's attached to, assets included.
Fix: Attach it to the default behaviour for pages only, and give /_next/static/* and other asset paths their own behaviours without it.
Gotcha: A function has a DEVELOPMENT and a LIVE stage: saving new code in the console, or deploying it with publish set to false, leaves the distribution running the old LIVE version.
Fix: Keep publish: true in code (the default), and test the new code with aws cloudfront test-function before it goes live.
Gotcha: On a flat-rate plan, a function, and its KeyValueStore, can't be shared with another distribution.
Fix: Create one function per distribution in code, from the same source.
Provisioning
Official Pulumi package · Official Terraform provider
@pulumi/aws cloudfront.Function, with the code inline and publish: true, attached to a cache behaviour as a viewer-request function association.
Instead, consider
- Amazon CloudFront The distribution it runs on: headers policies, cache policies and error pages are settings there, not code.
- Cloudflare static hosting A site that can live anywhere: index pages, trailing slashes and redirects with nothing to write.
- Cloudflare Workers Real logic at the edge: network calls, the request body, libraries.
Decision guides
Sources
- CloudFront Functions or Lambda@Edge
- Restrictions on CloudFront Functions
- CloudFront pay-as-you-go pricing
- Flat-rate plans: features by tier
Last reviewed by Nicolas Dao