AEM Edge Functions aem-edge-functions
AEM Edge Functions lets you execute JavaScript at the CDN layer, bringing data processing closer to the end user. This reduces latency and enables responsive, dynamic experiences without a round trip to your origin.
Common use cases include:
- Personalizing content based on information like geolocation, device type, or user attributes
- Acting as middleware between the CDN and your origin
- Reformatting or aggregating responses from third-party APIs before they reach the browser
- Composing and serving server-rendered HTML at the edge using content stitched from multiple backends
AEM Edge Functions is compatible with both Edge Delivery Services and the AEM as a Cloud Service Java-stack.
Key Benefits key-benefits
Prerequisites prerequisites
- An AEM as a Cloud Service environment
- The AEM Administrator Product Profile on the author instance of your Cloud Service environment, or the Cloud Manager Deployment Manager role in Admin Console for Edge Delivery Services sites
- Node.js and npm
Setup setup
Install the Adobe CLI install-adobe-cli
Install the Adobe Developer CLI (aio):
npm install -g @adobe/aio-cli
Install the AEM Edge Functions plugin:
aio plugins install @adobe/aio-cli-plugin-aem-edge-functions
Authenticate and configure the plugin for your environment:
aio login
aio aem edge-functions setup
The setup command prompts you to sign in and then select the AEM environment on which you want to use AEM Edge Functions.
Clone the Boilerplate boilerplate
Copy the aem-edge-functions-boilerplate to your own repository, then install dependencies:
npm install
Create Your First Function create-your-function
AEM Edge Function services are declared in a YAML configuration file and deployed through the Cloud Manager configuration pipeline.
1. Set Up a Configuration Pipeline configuration-pipeline
Before creating an edge function, ensure that a configuration pipeline exists for your environment in Cloud Manager. If not, create a configuration pipeline first.
aio aem rde:install -t env-config ./config instead of going through a configuration pipeline.2. Declare Your Edge Function Services declare-services
Create a file named edgeFunctions.yaml in your configuration directory:
kind: "EdgeFunctions"
version: "1"
data:
services:
- name: my-edge-function
# Uncomment to enable secrets
# secrets:
# - key: API_TOKEN
# value: ${{ API_TOKEN_SECRET }}
The default limit is 1 function for AEM as a Cloud Service environments and 3 for Edge Delivery Services sites. The top-level keys are:
servicesname.configssecretskvs3. Add CDN Origin Selector Rules cdn-routing
Edge functions are invoked by routing CDN traffic to them via origin selector rules. Add the following to your cdn.yaml configuration file (or create one if it does not exist):
kind: 'CDN'
version: '1'
data:
originSelectors:
rules:
- name: route-weather-to-edge-function
when: { reqProperty: path, equals: "/weather" }
action:
type: selectAemOrigin
originName: edgefunction-my-edge-function
- name: route-hello-world-to-edge-function
when: { reqProperty: path, equals: "/hello-world" }
action:
type: selectAemOrigin
originName: edgefunction-my-edge-function
The origin selector rules let you route traffic to your edge functions based on any condition available in the CDN rules engine, such as a specific path, domain, or request header. Multiple rules can route different paths to the same edge function. See Origin Selectors for the full rule syntax.
4. Deploy the Configuration deploy-configuration
Commit both edgeFunctions.yaml and cdn.yaml to your Cloud Manager Git repository and trigger the configuration pipeline. Once the pipeline completes successfully, your edge function endpoints are available at:
publish-pXXXXX-eYYYYY.adobeaemcloud.com/weatherpublish-pXXXXX-eYYYYY.adobeaemcloud.com/hello-world
where pXXXXX-eYYYYY are your environment coordinates. If a custom domain is configured, the functions are also reachable at those domain paths (for example, example.com/weather).
Build and Deploy AEM Edge Function Code build-deploy
Build build
Package your edge function code for deployment:
aio aem edge-functions build
Deploy deploy
Deploy the built package to a named edge function service. The function-name argument must match the name value in edgeFunctions.yaml:
aio aem edge-functions deploy <function-name>
Local Development local-development
Run Locally local-run
Start a local development server at http://127.0.0.1:7676:
aio aem edge-functions serve
See this Compute JavaScript documentation for details on what the local runtime supports.
Test test
Run the test suite with Mocha:
npm run test
Remote Debugging remote-debugging
Adobe Managed CDN does not expose a remote debugger, but does expose log streaming. Tail the logs for a deployed function to receive console.log output directly in your terminal:
aio aem edge-functions tail-logs <function-name>
Caching and Cache Purging caching
Edge Functions can significantly reduce origin load and improve response times by caching data at the edge. However, caching requires intentional design — particularly in Edge Functions where two independent cache layers are involved:
Browser → AEM CDN (CDN Cache) → AEM Edge Functions (Fetch Cache) → Backend (AEM, APIs, etc.)
Before configuring caching, consider how your content behaves:
- Truly unique-per-request content (session tokens, real-time pricing for a specific user) should bypass caching to avoid serving incorrect results.
- Cohort-based personalization (content tailored by region, device type, or audience segment) can often be cached with shorter TTLs or
Varyheaders, since many users share the same variant. - Stable, shared content (product catalogs, CMS pages, API responses that change on a known schedule) benefits from aggressive caching with explicit invalidation via surrogate keys.
- Getting it wrong in either direction has consequences. Over-caching causes stale content bugs that are difficult to diagnose across two cache layers. Under-caching defeats the performance and origin-offload purpose of using Edge Functions at all.
Because the CDN and the Edge Function’s internal fetch cache operate independently, a change to underlying data requires deliberate invalidation of both layers. Understanding this architecture is essential for reliable cache management.
For the detailed technical guidance on configuring caching behavior, controlling cache lifetimes, using surrogate keys, and purging cached content, see Caching in AEM Edge Functions.
Limitations limitations
Each Edge Function invocation runs inside a sandbox with resource limits enforced by the underlying compute platform.
Maximum Outbound Fetch Calls per Invocation max-fetch-calls
AEM Edge Functions enforce a hard limit of 32 backend requests per execution (that is, per incoming request handled by your function). Once this limit is reached, any further fetch() calls fail with the following error:
Requested backend named '…' does not exist
When you see this error and your origin configuration is correct, the most likely cause is that the per-invocation backend request quota has been exhausted. See Fastly Compute resource limits for the full list of platform limits.
Configuration Reference configuration-reference
Origins origins
By default, edge functions can fetch from any origin. To restrict a function to a defined set of origins, declare them under origins in edgeFunctions.yaml:
origins:
- name: my-origin-name
domain: example.com
Reference the named origin in your function code using the backend fetch option:
const request = new Request("https://example.com/test");
const response = await fetch(request, { backend: "my-origin-name" });
configs, secrets, and kvs) are not available in sandbox programs. Edge function services themselves run normally on sandbox environments — only the stores are not provisioned.Service Configuration service-configuration
Expose environment variables to your functions using the configs key in edgeFunctions.yaml. Values are stored in a config store named config_default:
configs:
- key: LOG_LEVEL
value: DEBUG
Read configuration values in your function code:
import { ConfigStore } from "fastly:config-store";
const config = new ConfigStore('config_default');
const logLevel = config.get('LOG_LEVEL') || 'info';
- The config store is always named
config_default. - Key names are case-sensitive.
- The config store is shared across all edge function services in the same environment.
Service Secrets service-secrets
Secrets are referenced, not stored, in edgeFunctions.yaml. The value field must point to a Cloud Manager secret using the ${{SECRET_REFERENCE}} syntax. Define the underlying secret in Cloud Manager first — see Cloud Manager Secret Variables.
secrets:
- key: API_TOKEN
value: ${{ API_TOKEN_SECRET }}
Retrieve secrets in your function code using the SecretStoreManager helper from the boilerplate:
import { SecretStoreManager } from "./lib/config";
const apiToken = await SecretStoreManager.getSecret('API_TOKEN');
- The secret store is always named
secret_default. - Key names are case-sensitive.
- Secrets are immutable once created.
- The secret store is shared across all edge function services in the same environment.
Service KV Store service-kv-store
Edge functions can read and write arbitrary key-value data at runtime through a KV store. To enable it, set kvs: true in edgeFunctions.yaml:
kvs: true
This provisions an empty KV store named kv_default. Populate it at runtime from your edge function code using the Fastly KV Store API:
import { KVStore } from "fastly:kv-store";
const kv = new KVStore('kv_default');
// Read a value
const entry = await kv.get('visit-count');
const count = entry ? Number(await entry.text()) : 0;
// Write a value
await kv.put('visit-count', String(count + 1));
- The KV store is always named
kv_default. - The KV store is empty at provision time; populate it at runtime via the Fastly KV Store API. Declarative key/value entries in
edgeFunctions.yamlare not supported. - The KV store is shared across all edge function services in the same environment.
Logging logging
AEM Edge Functions integrates with the AEM Log Forwarding feature. Create a logForwarding.yaml file alongside your edgeFunctions.yaml:
kind: "LogForwarding"
version: "1"
metadata:
envTypes: ["rde", "dev", "stage", "prod"]
data:
splunk:
default:
enabled: true
host: "splunk-host.example.com"
token: "${{SPLUNK_TOKEN}}"
index: "AEMaaCS"
Use the logger in your function code to write structured log entries:
import { Logger } from "fastly:logger";
const logger = new Logger("customerSplunk");
logger.log(JSON.stringify({
method: event.request.method,
url: event.request.url
}));