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.yaml to your content location, for example https://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.yaml in the repo. It defines the query-index.json feed 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 name to your Worker name.
  • Set the EDS_ORIGIN var to your live origin, https://main--<repo>--<org>.aem.live (production must use the .aem.live host so publish invalidation fires).
  • Put the R2 bucket name under the NEXT_INC_CACHE_R2_BUCKET binding.
  • Put the KV namespace id (printed by the create command) under the NEXT_TAG_CACHE_KV binding.

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_SECRET as 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_dispatch event (resource-published). The included Revalidate on publish workflow 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.

Request flow: the browser hits the Cloudflare Worker, which renders Next.js at the edge and fetches .plain.html from the Edge Delivery origin on a cache miss; when an author publishes, push invalidation purges the matching page cache tag.

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.