Next-Cloudflare-Turbo Logo Mark@nct

Environment Variables

Using environment variables in Cloudflare Workers

Open in Github

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.

.env.development
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:

/app/.dev.vars
NEXTJS_ENV=development
The production environment is used by default when NEXTJS_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:

  1. 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.

  2. Runtime configuration: Additionally set runtime variables and secrets on your Worker (see Production runtime below).

For more information on setting up Cloudflare Builds, see Automatic Deployments

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
For a list of Wrangler secret commands, see the Cloudflare documentation

After 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_SECRET

Worker 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:

db.ts
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:

.env.development
NEXT_PUBLIC_ANALYTICS_KEY=dev-analytics-123

Use 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_KEY

When prompted, enter your production value:

? Enter a secret value: » prod-analytics-789

Then deploy:

npm run deploy

Even 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:

  1. Navigate to Workers & Pages → your project → Settings → Builds
  2. Scroll to Environment variables
  3. 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:

.env.development
CMS_API_KEY=dev-cms-key-123

Use in your application

app/blog/[slug]/page.tsx
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:

.env.production
CMS_API_KEY=prod-cms-key-789

Then build and deploy:

npm run deploy

The 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:

  1. Navigate to Workers & Pages → your project → SettingsBuilds
  2. Scroll to Environment variables
  3. Add secret:
    • Variable name: CMS_API_KEY
    • Value: prod-cms-key-789
    • Type: Secret

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

ContextWhere to set themHow to read them
Local next dev.env.local or .env.developmentprocess.env.*
Local Workers preview.env* for variables, optional .dev.vars for NEXTJS_ENV; wrangler.jsonc for bindingsprocess.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 secretsUsed at next build time remotely, NEXT_PUBLIC_* inlined
Runtime on CloudflareWrangler command → Variables and Secrets; wrangler.jsonc for bindingsprocess.env.* (variables/secrets); getCloudflareContext().env (bindings)

FAQs

How is this guide?

Last updated on