Getting Started
This is a step-by-step guide to standing up your own copy of this project: an AEM Edge Delivery Services site rendered through a Next.js app that runs as a Cloudflare Worker. By the end you will have local development running, the app deployed to your own domain, and content updates going live automatically when an author publishes.
What you'll build — content authored in Edge Delivery, rendered by the Next.js Worker at the edge.
Prerequisites
- A GitHub account (you will host the code and use GitHub Actions).
- A Cloudflare account with a domain (zone) already added to it.
- A content source: Adobe Document Authoring (or a SharePoint/Google Drive mount) connected to an aem.live project.
- Node.js 18 or newer (this project is developed on Node 22).
- The AEM CLI:
npm install -g @adobe/aem-cli.
1. Get the code
Fork this repository into your own GitHub account, then clone it and install dependencies:
git clone https://github.com/<your-org>/next-eds.git
cd next-eds
nvm use 22
npm install
2. Connect your content source
Edge Delivery serves the content; the Next.js app only renders it. Point the project at your content source and let it index pages.
- Set the mount point in
fstab.yamlto your content location, for examplehttps://content.da.live/<your-org>/<your-repo>/. - Install the AEM Code Sync GitHub app on your repository so Edge Delivery picks up code changes.
- Keep
helix-query.yamlin the repo. It defines thequery-index.jsonfeed that powers static generation and the navigation mega-menu. Edge Delivery generates the feed as pages are published.
3. Run it locally
Local development runs the AEM CLI as the content origin, with the Next.js dev server rendering on top of it.
aem up # Edge Delivery content at http://localhost:3000
In a second terminal, start the renderer on a different port and point it at the local content:
EDS_ORIGIN=http://localhost:3000 npm run dev -- -p 3001
Open http://localhost:3001. To render remote content instead, point EDS_ORIGIN at a preview or live origin (for example https://main--<repo>--<org>.aem.page) and run npm run dev on its own.
4. Set up Cloudflare
The app is compiled by OpenNext into a single Worker. Create the backing resources and wire them into wrangler.jsonc.
npx wrangler login
npx wrangler r2 bucket create <your-app>-cache # backs the ISR incremental cache
npx wrangler kv namespace create <your-app>-tag-cache # backs revalidateTag (instant publish)
Then edit wrangler.jsonc:
- Set
nameto your Worker name. - Set the
EDS_ORIGINvar to your live origin,https://main--<repo>--<org>.aem.live(production must use the.aem.livehost so publish invalidation fires). - Put the R2 bucket name under the
NEXT_INC_CACHE_R2_BUCKETbinding. - Put the KV namespace id (printed by the create command) under the
NEXT_TAG_CACHE_KVbinding.
Finally, set the shared secret that protects the revalidation endpoint:
npx wrangler secret put REVALIDATE_SECRET
5. Deploy
Deploy manually from your machine:
npm run deploy:cf # builds with OpenNext and deploys the Worker
Or let CI deploy on every push to main. Add two repository secrets in GitHub — CLOUDFLARE_API_TOKEN and CLOUDFLARE_ACCOUNT_ID — and the included Deploy Cloudflare Worker workflow will build and deploy automatically.
6. Wire your custom domain
In wrangler.jsonc, add your domain to routes as a custom domain (route both the apex and www so the app can redirect www to the apex). The zone must already exist in your Cloudflare account; on deploy, wrangler provisions the DNS record and TLS certificate.
"routes": [
{ "pattern": "example.com", "custom_domain": true },
{ "pattern": "www.example.com", "custom_domain": true }
]
7. Turn on instant updates when authors publish
So published content appears without waiting for a cache to expire, wire Edge Delivery's publish events to the revalidation workflow.
- Add
REVALIDATE_SECRETas a GitHub repository secret, using the same value you set on the Worker. - Configure Edge Delivery to send publish notifications to your repository as a
repository_dispatchevent (resource-published). The includedRevalidate on publishworkflow turns the published path into a page slug and calls/api/revalidate, which clears that page from the Worker cache so the next request re-renders from fresh content.
You can also revalidate on demand from the Actions tab: run the Revalidate on publish workflow with a path (or * to revalidate every published page).
8. Verify
- Publish a page from your content source, then visit your domain and confirm the change is live.
- Run the page through PageSpeed Insights and aim for a score of 100 — most content ships as server-rendered HTML with no client JavaScript, so the performance profile matches native Edge Delivery.
How it fits together
The browser always talks to the Cloudflare Worker, which renders Next.js at the edge and serves cached HTML. On a cache miss it fetches the page's .plain.html from the Edge Delivery origin, renders it, and caches the result tagged with page:<slug>. When an author publishes, Edge Delivery push invalidation purges the matching tag, so the next request re-renders from fresh content.
Where to go next
- Read Architecture at a glance to see how a request flows through the Worker.
- Read How to Build a New Block to add your own blocks, either the classic Edge Delivery way or as React components.