Next.js
Step-by-step guide to deploying a Next.js application to Cloudflare Workers using Alchemy.
This guide demonstrates how to deploy a Next.js application to Cloudflare using Alchemy with full-stack capabilities including server actions and API routes.
Start by creating a new Next.js project using Alchemy:
bunx alchemy create my-nextjs-app --template=nextjscd my-nextjs-appnpx alchemy create my-nextjs-app --template=nextjscd my-nextjs-apppnpm dlx alchemy create my-nextjs-app --template=nextjscd my-nextjs-appyarn dlx alchemy create my-nextjs-app --template=nextjscd my-nextjs-appBefore you can deploy, authenticate with your Cloudflare account:
bun alchemy loginnpx alchemy loginpnpm alchemy loginyarn alchemy loginDeploy
Section titled “Deploy”Run the deploy script to build and deploy your Next.js application:
bun run deploynpm run deploypnpm run deployyarn run deployYou’ll get the live URL of your Next.js site:
{ url: "https://website.<your-account>.workers.dev"}Local Development
Section titled “Local Development”Work locally using the dev script:
bun run devnpm run devpnpm run devyarn run devDestroy
Section titled “Destroy”Clean up all Cloudflare resources created by this stack:
bun run destroynpm run destroypnpm run destroyyarn run destroyWhat files are created
Section titled “What files are created”Alchemy requires a locally set password to encrypt Secrets that are stored in state. Be sure to change this.
ALCHEMY_PASSWORD=change-mealchemy.run.ts
Section titled “alchemy.run.ts”The infrastructure setup with KV storage for demonstration:
/// <reference types="@types/node" />
import alchemy from "alchemy";import { KVNamespace, Nextjs } from "alchemy/cloudflare";
const app = await alchemy("my-nextjs-app");
export const kv = await KVNamespace("kv");
export const website = await Nextjs("website", { adopt: true, bindings: { KV: kv },});
console.log({ url: website.url,});
await app.finalize();types/env.d.ts
Section titled “types/env.d.ts”Type-safe access to Cloudflare bindings:
// Auto-generated Cloudflare binding types.// @see https://alchemy.run/concepts/bindings/#type-safe-bindings
import type { website } from "../alchemy.run.ts";
export type CloudflareEnv = typeof website.Env;
declare global { type Env = CloudflareEnv;}
declare module "cloudflare:workers" { namespace Cloudflare { export interface Env extends CloudflareEnv {} }}tsconfig.json
Section titled “tsconfig.json”The CLI updated the tsconfig.json to include alchemy.run.ts and register @cloudflare/workers-types + types/env.d.ts globally:
{ "compilerOptions": { "lib": ["dom", "dom.iterable", "es6"], "allowJs": true, "skipLibCheck": true, "strict": true, "noEmit": true, "esModuleInterop": true, "module": "esnext", "moduleResolution": "bundler", "resolveJsonModule": true, "isolatedModules": true, "jsx": "preserve", "incremental": true, "plugins": [ { "name": "next" } ], "paths": { "@/*": ["./src/*"] }, "types": ["@cloudflare/workers-types", "./types/env.d.ts"] }, "include": [ "next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts", "alchemy.run.ts" ], "exclude": ["node_modules"]}next.config.ts
Section titled “next.config.ts”Configure Next.js for Cloudflare Workers with OpenNext:
import { initOpenNextCloudflareForDev } from "@opennextjs/cloudflare";import type { NextConfig } from "next";
const nextConfig: NextConfig = { /* config options here */ typescript: { ignoreBuildErrors: true, },};
export default nextConfig;
initOpenNextCloudflareForDev();open-next.config.ts
Section titled “open-next.config.ts”Configure OpenNext for Cloudflare Workers deployment:
import { defineCloudflareConfig } from "@opennextjs/cloudflare";
export default defineCloudflareConfig({ // Uncomment to enable R2 cache, // It should be imported as: // `import r2IncrementalCache from "@opennextjs/cloudflare/overrides/incremental-cache/r2-incremental-cache";` // See https://opennext.js.org/cloudflare/caching for more details // incrementalCache: r2IncrementalCache,});Using Cloudflare Bindings
Section titled “Using Cloudflare Bindings”The template includes examples of accessing Cloudflare bindings in both API routes and Server Components.
In API Routes
Section titled “In API Routes”import { getCloudflareContext } from "@opennextjs/cloudflare";
export const GET = async () => { const { env } = getCloudflareContext(); const values = await env.KV.list(); return Response.json(values);};In Server Components
Section titled “In Server Components”import { getCloudflareContext } from "@opennextjs/cloudflare";import { revalidatePath } from "next/cache";
export default async function Home() { const { env } = await getCloudflareContext({ async: true }); const values = await env.KV.list();
return ( <div> <h1>KV Values</h1> <pre>{JSON.stringify(values, null, 2)}</pre> <button onClick={putValue}>Put Value</button> <button onClick={deleteValue}>Delete Value</button> </div> );}
const putValue = async () => { "use server";
const { env } = await getCloudflareContext({ async: true }); await env.KV.put(crypto.randomUUID(), "test"); revalidatePath("/");};
const deleteValue = async () => { "use server";
const { env } = await getCloudflareContext({ async: true }); const values = await env.KV.list(); await Promise.all(values.keys.map((key) => env.KV.delete(key.name))); revalidatePath("/");};Advanced Features
Section titled “Advanced Features”Incremental Static Regeneration (ISR)
Section titled “Incremental Static Regeneration (ISR)”Next.js ISR is supported through R2 caching. Uncomment the cache configuration in open-next.config.ts to enable:
import r2IncrementalCache from "@opennextjs/cloudflare/overrides/incremental-cache/r2-incremental-cache";
export default defineCloudflareConfig({ incrementalCache: r2IncrementalCache,});Image Optimization
Section titled “Image Optimization”Next.js Image optimization works automatically with Cloudflare’s image transformation service.
Middleware
Section titled “Middleware”Edge middleware is fully supported and runs on Cloudflare’s edge network for optimal performance.
Deployment Notes
Section titled “Deployment Notes”- The build process uses OpenNext to transform your Next.js app for Cloudflare Workers
- All Next.js features including App Router, Server Components, and Server Actions are supported
- Static assets are automatically uploaded to Cloudflare R2 and served via CDN
- The
wrangler.jsoncfile is auto-generated and should be added to.gitignore
If you see warnings about wrangler.jsonc not being ignored, add it to your .gitignore file to prevent it from being committed to your repository.