Next.js
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-app
npx alchemy create my-nextjs-app --template=nextjscd my-nextjs-app
pnpm dlx alchemy create my-nextjs-app --template=nextjscd my-nextjs-app
yarn dlx alchemy create my-nextjs-app --template=nextjscd my-nextjs-app
Before you can deploy, authenticate with your Cloudflare account:
bun alchemy login
npx alchemy login
pnpm alchemy login
yarn alchemy login
Deploy
Section titled “Deploy”Run the deploy script to build and deploy your Next.js application:
bun run deploy
npm run deploy
pnpm run deploy
yarn run deploy
You’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 dev
npm run dev
pnpm run dev
yarn run dev
Destroy
Section titled “Destroy”Clean up all Cloudflare resources created by this stack:
bun run destroy
npm run destroy
pnpm run destroy
yarn run destroy
What 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-me
alchemy.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.jsonc
file 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.