Environment Variables
Using environment variables in Cloudflare Workers
There are two categories of configuration to think about:
- Environment variables: API keys, feature flags, config strings, etc.
- Worker bindings: Cloudflare resources such as D1, KV, R2 or Durable Objects.
The distinction matters because the way you access each is different.
Environment variables
Using .env files ensures that environment variables are available on process.env both when running next dev and when running your app locally on a Worker with wrangler dev.
You can follow typical Next.js conventions where you have either a single .env file, or environment specific files such as .env.development.
.env
When you run next dev, these are automatically loaded and can be accessed with process.env. When previewing your app under Workers (with npm run preview), you'll still use .env* for most values.
API_BASE_URL=http://localhost:3000
NEXT_PUBLIC_ANALYTICS_KEY=dev-123.dev.vars
You can use the NEXTJS_ENV environment variable to select which environment to use when running your app locally on a Worker. To use the development environment, create a .dev.vars file:
NEXTJS_ENV=developmentNEXTJS_ENV is not explicitly set, therefore you won't need to consider this in production.Production builds
Cloudflare does not see your local .env files. When deploying to production, you must configure your environment variables and secrets separately.
Deploying via CLI
When deploying via the CLI using npm run deploy, Wrangler will use the variables and secrets you have previously configured via Wrangler commands (see Adding secrets below).
Your .env files remain local and are never uploaded to Cloudflare. Before your first deployment, ensure you have set all required secrets and variables using Wrangler commands.
Deploying via Cloudflare Builds
If you are using Cloudflare Builds for automatic deployments, you must set variables and secrets in two places:
-
Build configuration: Set build-time variables and secrets in your build configuration. The Worker needs access to inline any
NEXT_PUBLIC_*variables, and access to non-NEXT_PUBLIC_*variables needed for statically generated pages. -
Runtime configuration: Additionally set runtime variables and secrets on your Worker (see Production runtime below).
Production runtime
If you need to access variables at runtime, you must additionally add them to your Worker's Variables and Secrets configuration (a separate configuration to the ones used in a the build configuration).
Adding secrets
Secrets are encrypted, and once set cannot be read back again. The main way to set Secrets is via Wrangler:
npx wrangler secret put KEY [options]KEY(required). The variable name for this secret to be accessed in the Worker.--env(optional). Perform on a specific environment, e.g.--production
secret commands, see the Cloudflare documentationAfter running this command, you will be prompted to input the actual value. Paste it into the terminal:
⛅️ wrangler 4.28.0
─────────────────────────────────────────────
? Enter a secret value: » ****Wrangler will then confirm success:
⛅️ wrangler 4.28.0
─────────────────────────────────────────────
√ Enter a secret value: ... ****
🌀 Creating the secret for the Worker "next-cloudflare-turbo"
✨ Success! Uploaded secret TEST_SECRETWorker bindings
Bindings are treated differently to environment variables. Bindings represent Cloudflare resources such as the D1 database, R2 buckets etc.
The OpenNext adapter provides a getCloudflareContext() function for exactly this:
import { createDrizzleD1 } from "@nct/db"
import { getCloudflareContext } from "@opennextjs/cloudflare"
export const getDb = cache(() => {
const { env } = getCloudflareContext()
return createDrizzleD1(env.DB)
})Examples
Client-side public variable (NEXT_PUBLIC_*)
Let's walk through adding a public analytics key that needs to be available on the client side.
Local development
Add the variable to your .env file:
NEXT_PUBLIC_ANALYTICS_KEY=dev-analytics-123Use in your application
"use client"
export function Analytics() {
const analyticsKey = process.env.NEXT_PUBLIC_ANALYTICS_KEY
// Your analytics implementation
return <script data-key={analyticsKey} />
}Production deployment (CLI)
When deploying via CLI, NEXT_PUBLIC_* variables must be available at build time so Next.js can inline them into your client bundles.
Set the variable as a Wrangler variable (not a secret, as it will be publicly visible in your client bundle):
npx wrangler secret put NEXT_PUBLIC_ANALYTICS_KEYWhen prompted, enter your production value:
? Enter a secret value: » prod-analytics-789Then deploy:
npm run deployEven though we use wrangler secret put, NEXT_PUBLIC_* variables are not kept secret. They are inlined into your client JavaScript bundle and visible to anyone.
Production deployment (Cloudflare Builds)
Configure the variable in your build settings:
- Navigate to Workers & Pages → your project → Settings → Builds
- Scroll to Environment variables
- Add variable:
- Variable name:
NEXT_PUBLIC_ANALYTICS_KEY - Value:
prod-analytics-789 - Type: Variable (not Secret)
The build system will inline this value during next build.
Build-time variable (SSG)
Let's walk through adding a CMS API key that's needed to fetch content during static site generation.
Local development
Add the variable to your .env file:
CMS_API_KEY=dev-cms-key-123Use in your application
import { notFound } from "next/navigation"
async function getPost(slug: string) {
const response = await fetch(`https://cms.example.com/posts/${slug}`, {
headers: {
'Authorization': `Bearer ${process.env.CMS_API_KEY}`
}
})
if (!response.ok) return null
return response.json()
}
export async function generateStaticParams() {
const response = await fetch('https://cms.example.com/posts', {
headers: {
'Authorization': `Bearer ${process.env.CMS_API_KEY}`
}
})
const posts = await response.json()
return posts.map((post) => ({ slug: post.slug }))
}
export default async function BlogPost({ params }: { params: { slug: string } }) {
const post = await getPost(params.slug)
if (!post) notFound()
return (
<article>
<h1>{post.title}</h1>
<div>{post.content}</div>
</article>
)
}Production deployment (CLI)
For CLI deployment, the build happens locally on your machine. Set the variable in your .env.production file:
CMS_API_KEY=prod-cms-key-789Then build and deploy:
npm run deployThe next build step will use the variable from .env.production to generate your static pages.
Build-time variables used for SSG do not need to be configured as Wrangler secrets, as they're only needed during the build process on your local machine.
Production deployment (Cloudflare Builds)
When using Cloudflare Builds, the build happens on Cloudflare's servers. Configure the variable in your build settings:
- Navigate to Workers & Pages → your project → Settings → Builds
- Scroll to Environment variables
- Add secret:
- Variable name:
CMS_API_KEY - Value:
prod-cms-key-789 - Type: Secret
- Variable name:
The build system will have access to this secret during next build to generate your static pages.
If this variable is only used at build time for SSG, you do not need to add it to the Worker's runtime Variables and Secrets. It's only needed in the build configuration.
Summary
| Context | Where to set them | How to read them |
|---|---|---|
Local next dev | .env.local or .env.development | process.env.* |
| Local Workers preview | .env* for variables, optional .dev.vars for NEXTJS_ENV; wrangler.jsonc for bindings | process.env.* (variables); getCloudflareContext().env (bindings) |
| Build (CLI) | .env.production or .env* | Used at next build time locally; NEXT_PUBLIC_* inlined |
| Build (Cloudflare) | Dashboard → Build variables and secrets | Used at next build time remotely, NEXT_PUBLIC_* inlined |
| Runtime on Cloudflare | Wrangler command → Variables and Secrets; wrangler.jsonc for bindings | process.env.* (variables/secrets); getCloudflareContext().env (bindings) |
FAQs
How is this guide?
Last updated on