How to Set Up Wrangler for Cloudflare Workers Development
Install and configure Wrangler for local Cloudflare Workers and Pages development, including environment variables, KV bindings, secrets, environments, and deployment.
Wrangler is Cloudflare’s command-line tool for developing and deploying Workers and Pages projects. Install it locally in the repository, authenticate with wrangler login, run the local simulator with the project’s bindings, and keep production secrets and resource IDs out of source control.
Workers and Pages are different workflows
Wrangler supports both products, but the commands are not interchangeable:
- Workers deploy a Worker entry point with
wrangler deploy. - Pages deploy a built static output directory with
wrangler pages deploy. - A Pages project can still use server-rendered functions or an adapter, but the build and deployment configuration determines which command applies.
If the project uses Astro on Cloudflare Pages, follow How to Deploy an Astro Content Site on Cloudflare Pages for the build, adapter, and Git-backed workflow. This guide focuses on the Wrangler CLI and local bindings.
Step 1 — Install Wrangler locally
A local dev dependency keeps the CLI version consistent across developers and CI:
npm install --save-dev wrangler
Run it with npx or a package script:
npx wrangler --version
A global installation can be convenient for occasional commands, but a repository-local version is easier to reproduce. Do not mix an old global binary with a newer project version when diagnosing behavior.
Step 2 — Log in and inspect the account
Authenticate interactively:
npx wrangler login
npx wrangler whoami
The login opens a browser and grants the CLI access to an account. If you work with multiple accounts, check whoami before creating a namespace or deploying. A successful login does not mean the token has permission for every resource.
For automation, use a narrowly scoped API token supplied through the CI secret store. Never put a token in wrangler.toml, .dev.vars, a shell transcript committed to the repository, or a client-side bundle.
Step 3 — Initialize a Worker
For a new Worker project:
mkdir my-worker
cd my-worker
npm init -y
npm install --save-dev wrangler
npx wrangler init
Wrangler creates or asks about a configuration file and entry point. A minimal wrangler.toml can look like this:
name = "my-worker"
main = "src/index.ts"
compatibility_date = "2026-08-17"
Use the repository’s existing configuration if you are joining a project. Do not replace a working file merely to match this minimal example; bindings, routes, compatibility flags, and build settings are application-specific.
Step 4 — Run the local dev server
Start local development with:
npx wrangler dev
Wrangler serves the Worker locally and reloads it as source files change. A basic Worker entry point might be:
export default {
async fetch(request: Request): Promise<Response> {
const url = new URL(request.url);
return new Response(`path: ${url.pathname}`);
},
};
The local server is useful for testing request routing, headers, bindings, and errors before deployment. It is not a complete substitute for testing the deployed edge behavior, especially when production uses custom domains, WAF rules, queues, or remote data.
Step 5 — Add local environment variables
Non-secret local variables can be declared in .dev.vars:
API_BASE_URL="http://localhost:3000"
FEATURE_FLAG="local"
Keep .dev.vars in .gitignore. For local secrets, use the same file only if the project explicitly expects that behavior and protect the file with normal filesystem permissions. Do not print secret values in logs or return them from a test endpoint.
The Worker reads variables from its env parameter rather than from process.env:
interface Env {
API_BASE_URL: string;
FEATURE_FLAG: string;
}
export default {
async fetch(_request: Request, env: Env): Promise<Response> {
return Response.json({
api: env.API_BASE_URL,
feature: env.FEATURE_FLAG,
});
},
};
Step 6 — Configure a KV binding
Create a namespace through Wrangler:
npx wrangler kv namespace create CACHE
Add the returned ID to the configuration. The binding name is the property your code uses:
[[kv_namespaces]]
binding = "CACHE"
id = "replace-with-the-real-namespace-id"
Use it in the Worker:
interface Env {
CACHE: KVNamespace;
}
export default {
async fetch(_request: Request, env: Env): Promise<Response> {
const current = Number((await env.CACHE.get("visits")) || "0");
const next = String(current + 1);
await env.CACHE.put("visits", next);
return new Response(`visits: ${next}`);
},
};
A binding name such as CACHE is not the same thing as the namespace’s display name. If the code sees undefined, compare the binding value, the TypeScript Env interface, and the configuration loaded by the current Wrangler environment.
Step 7 — Store production secrets
Set a secret interactively or from a protected CI process:
npx wrangler secret put API_TOKEN
Read it from the env object at runtime. Keep secret names in documentation or an .env.example, but never commit their values. Rotate a credential if it has appeared in a terminal recording, issue, log, or repository history.
Step 8 — Separate staging and production
Named environments let you use different Worker names, bindings, and secrets:
[env.staging]
name = "my-worker-staging"
[env.production]
name = "my-worker"
Add environment-specific bindings as required by the project. Deploy and set secrets for the intended environment explicitly:
npx wrangler deploy --env staging
npx wrangler secret put API_TOKEN --env staging
npx wrangler deploy --env production
Treat environment names as a safety boundary, not as a replacement for reviewing the target account and resource IDs. Check the command output before confirming a production deployment.
Step 9 — Deploy the correct product
For a Worker:
npx wrangler deploy
For a Pages build output directory:
npm run build
npx wrangler pages deploy dist
A repository connected to Cloudflare Pages may deploy automatically when its production branch changes. In that setup, a direct wrangler pages deploy is a separate deployment path and should not be used casually. Check DEPLOY.md, package.json, and the Cloudflare project settings first.
Step 10 — Inspect live logs
When a deployed Worker misbehaves, stream its request logs:
npx wrangler tail
Use filters when the project needs them, and avoid logging credentials, full authorization headers, or personal data. A tail session shows live observations; it does not replace structured error reporting or an application-level audit trail.
Troubleshooting
wrangleris not found — usenpx wrangleror confirm the localnode_modules/.binpath through an npm script.- Login succeeds but deployment is denied — run
wrangler whoami, confirm the account, and check the token or user permissions for the target project. - A binding is
undefinedlocally — verify the binding name and startwrangler devfrom the directory containing the intended configuration. - Local KV behavior differs from production — check whether the dev command is using a local or remote binding and test explicitly before changing data.
- Secrets are missing — remember that dashboard or deployed secrets do not automatically appear in every local process; use the project’s documented local-secret mechanism.
- The wrong thing deployed — distinguish
wrangler deployfromwrangler pages deploy, inspect the project name and environment, and confirm the output directory. - A request is blocked before it reaches the Worker — inspect Cloudflare Security Events and WAF/rate-limit rules. The Cloudflare WAF and rate-limiting guide covers the edge layer.
Summary
Use a repository-local Wrangler, authenticate deliberately, keep local variables and production secrets separate, declare bindings by the names the code consumes, and make the Worker-versus-Pages deployment path explicit. Test locally, inspect the target environment before deploying, and use wrangler tail without exposing sensitive request data.
Comments
One comment per thread every 30 minutes · edits are unlimited.