Setup guide
From an empty machine to a Worker running in production, in ten steps.
Install dependencies
Before creating a Worker project, install the following on your machine:
- npm — Node's package manager, used to install and run project tooling.
- Node.js — the JavaScript runtime that npm and Wrangler run on top of.
Create a Cloudflare Worker project
npm create cloudflareScaffolds a new Cloudflare Worker project, including the base folder structure and starter files.
Explore available Wrangler commands
npx wranglerLists the commands available in Wrangler, Cloudflare's CLI for building, testing, and deploying Workers.
Authenticate with Cloudflare
npx wrangler loginGrants Wrangler access to your Cloudflare account by opening a browser window to complete authentication.
Confirm which account you're using
npx wrangler whoamiVerifies which Cloudflare account you're currently logged in with — useful if you manage more than one account.
Deploy the project
npm run deployDeploys your code to Cloudflare's network. Run this from inside the project directory that holds your deployment files (the folder containing wrangler.toml/wrangler.json and your package.json).
Build and test locally
Wrangler lets you build and test your Worker on your machine before pushing it live, so you can catch issues before deployment.
npm startStarts a local development session so you can preview your Worker at localhost.
Edit and hot-reload
Test changes by editing the index.ts file, typically located inside the src directory of your project. Once you save the file, refresh the browser tab and your update should appear.
Preview in live mode
While npm start is running, press l on the same page to switch out of local mode and preview how the Worker behaves when it's actually running on Cloudflare's live infrastructure.
- Open DevTools, go to the Network tab, and click the request for your Worker.
- Check the Response Headers — you should see a
cf-rayheader, Cloudflare's unique request identifier for that call.
The header you're checking for is cf-ray — Cloudflare's per-request trace identifier (Ray ID). Seeing it confirms the request was served by Cloudflare's edge rather than your local dev server.
Verify and monitor the deployment
Once npm run deploy finishes, confirm the live version is actually working before you consider the job done:
- Open the URL returned in your terminal (e.g.
https://your-worker.your-subdomain.workers.dev) and confirm it matches what you tested locally. - Stream real-time logs from the live Worker to watch for runtime errors:
npx wrangler tailLeave this running while you exercise the live endpoint — request logs, exceptions, and console.log output stream to your terminal as they happen.
Beyond the basics
Project layout, secrets, custom domains, rollbacks, and juggling multiple client accounts.
Project structure
After Step 2, npm create cloudflare scaffolds a project with roughly this layout:
my-worker/
├── src/
│ └── index.ts # Worker entry point (edited in Step 8)
├── test/ # Sample tests for the Worker
├── wrangler.json # Wrangler configuration (or wrangler.toml)
├── package.json # npm scripts and dependencies
└── tsconfig.json # TypeScript configurationThe two files to know first are src/index.ts, where your Worker's logic lives, and wrangler.json/wrangler.toml, which controls how the project builds and deploys (see toml vs. json below).
Secrets & environment variables
Don't put API keys, tokens, or other sensitive values directly in wrangler.toml/wrangler.json — those files are typically checked into version control. Use secrets instead:
npx wrangler secret put API_KEYWrangler prompts you to paste the value, then encrypts and stores it on Cloudflare's side. It's available in your Worker via env.API_KEY but never appears in your source files or config.
Non-sensitive configuration (feature flags, environment names, public URLs) can go in the vars section of your Wrangler config file instead, since those values are fine to commit.
Custom domains & routes
By default, a deployed Worker is reachable at a *.workers.dev subdomain. To serve it from your own domain, attach a route or custom domain in your Wrangler config:
{
"routes": [
{ "pattern": "example.com/api/*", "zone_name": "example.com" }
]
}Or, for a dedicated subdomain fully managed by Cloudflare:
{
"routes": [
{ "pattern": "api.example.com", "custom_domain": true }
]
}The domain must already be onboarded to Cloudflare (using Cloudflare nameservers) before you can attach a route. Redeploy with npm run deploy after updating the config for the change to take effect.
Rolling back a deployment
If a deployment introduces a regression, you can revert to the previous version without redeploying old code by hand:
npx wrangler rollbackThis reverts the live Worker to the last known-good deployment. Use npx wrangler deployments list first if you need to see history and pick a specific version to roll back to.
Managing multiple client projects
Wrangler and npx are directory-aware — they read the wrangler.jsonc (or wrangler.toml) file from whatever directory you're in. That one file defines the project name, D1 bindings, worker entry point, secrets, and every other project-specific setting. There is no global project state. The golden rule: confirm your directory before running any command.
Three commands to run before every session
These take under ten seconds and prevent accidental cross-project changes:
pwd # which directory am I in?
cat wrangler.jsonc | grep '"name"' # does the project match the client?
npx wrangler whoami # which Cloudflare account is authenticated?If any of the three outputs doesn't match what you expect, stop and fix the mismatch before continuing. A deploy or database command against the wrong project or account can overwrite production data with no undo.
Switching between client projects
# Move to client A and confirm
cd ~/Projects/client-a
pwd
cat wrangler.jsonc | grep '"name"'
npm run dev # runs only for client-a
# Switch to client B
cd ~/Projects/client-b
pwd
cat wrangler.jsonc | grep '"name"'
npm run dev # runs only for client-bEach directory has its own node_modules, its own wrangler.jsonc, and its own D1 database IDs. Nothing bleeds between projects.
Recommended folder structure
~/Projects/
client-a/
wrangler.jsonc ← name: "client-a-app"
src/index.js
public/index.html
.dev.vars ← local secrets (never commit)
schema.sql
client-b/
wrangler.jsonc ← name: "client-b-app"
src/index.js
public/index.html
.dev.vars
schema.sqlEach project is self-contained. The .dev.vars file holds secrets for local development only — add it to .gitignore so it's never committed:
echo ".dev.vars" >> .gitignoreCommands that affect production vs. local only
Always confirm your directory and project name before running anything in the left column:
| Affects production — confirm first | Local only — safe anytime |
|---|---|
npm run deploy | npm run dev |
npx wrangler secret put X | npx wrangler d1 execute … --local |
npx wrangler d1 execute … --remote | npx wrangler whoami |
npx wrangler d1 create … | pwd |
npx wrangler rollback | cat wrangler.jsonc |
Show the full path in your terminal prompt
Add this to your ~/.zshrc so your current directory is always visible — you can't accidentally run a command in the wrong location:
export PS1="%F{green}%~%f %% "Apply it immediately without restarting your terminal:
source ~/.zshrcSwitching Cloudflare accounts between clients
If different clients use different Cloudflare accounts, log out of the current account and into the correct one before any deployment or database command:
npx wrangler logout
npx wrangler login
npx wrangler whoamiConfirm the account name matches the client before proceeding.
Signing out
Sign out of Wrangler when you finish a session — especially on a shared or temporary machine, or when switching between client Cloudflare accounts:
npx wrangler logoutThis revokes the local OAuth token created in Step 4, so the machine no longer has standing access to your Cloudflare account. The token is stored at:
~/.wrangler/config/default.tomlAfter logging out, the next command that requires authentication prompts you to run npx wrangler login again.
Any time you finish a client project before switching to another client's account, before handing a machine to someone else, or at the end of any session on a machine that isn't exclusively yours.
Full account switch sequence
Use this when moving between client accounts to ensure you're always authenticated as the correct user:
npx wrangler logout
cd ~/Projects/client-b
npx wrangler login
npx wrangler whoamiThe final whoami confirms the new account is active before you run anything that touches production.
Reference
The full command tables, the npm/npx distinction, and troubleshooting notes.
Local development & testing — command reference
All commands below are safe to run locally. None touch your production worker, remote database, or account settings unless the --remote flag is explicitly present.
Starting and stopping the local server
| Command | What it does |
|---|---|
npm run dev | Starts the local dev server. Worker runs at http://localhost:8787. File changes reload automatically. |
npx wrangler dev | Same as above — direct Wrangler invocation without the npm script. |
npx wrangler dev --port 9000 | Starts the local server on a custom port instead of the default 8787. |
npx wrangler dev --local | Forces fully local mode — local D1, KV, and bindings. No account calls at all. |
npx wrangler dev --remote | Runs code locally but bindings (D1, KV, secrets) connect to your real Cloudflare resources. |
| x while dev runs | Stops the local dev server cleanly. |
| r while dev runs | Force-reloads the worker without restarting the server. |
| b while dev runs | Opens the local worker URL in your default browser. |
| d while dev runs | Opens Chrome DevTools connected to the local worker. |
| l while dev runs | Toggles between local mode and live preview (connected to the edge). |
Local D1 database commands
| Command | What it does |
|---|---|
npx wrangler d1 create <db-name> | Creates a new D1 database on your account and prints the database_id to add to wrangler.jsonc. |
npx wrangler d1 execute <db-name> --local --file=schema.sql | Runs a SQL file against the local D1 database — create tables and seed data for local testing. |
npx wrangler d1 execute <db-name> --local --command="…" | Runs a one-off SQL query against the local database. |
npx wrangler d1 execute <db-name> --remote --file=schema.sql | Runs a SQL file against the production D1 database. Confirm project and account first. |
npx wrangler d1 execute <db-name> --remote --command="…" | Queries the production database directly. Reads are safe; destructive queries are permanent. |
npx wrangler d1 list | Lists all D1 databases in the current account. |
npx wrangler d1 info <db-name> | Shows details about a database including ID, region, and size. |
The local D1 database is a separate SQLite file on your machine — changes made with --local don't affect production. Run your schema against both --local and --remote when setting up a new project.
Secrets and environment variables
| Command | What it does |
|---|---|
npx wrangler secret put <KEY> | Prompts for a value and stores it as an encrypted secret on the production worker. Available as env.KEY. |
npx wrangler secret list | Lists all secrets on the production worker. Values are never shown — only key names. |
npx wrangler secret delete <KEY> | Removes a secret from the production worker. |
Create .dev.vars in project root | Local-only secrets. Format: KEY=value per line. Loaded automatically by wrangler dev. Never commit. |
# Example .dev.vars file
ADMIN_PIN=your-local-pin
API_KEY=your-local-api-keyAlways add .dev.vars to your .gitignore — it contains plaintext secrets for local use only.
echo ".dev.vars" >> .gitignoreLogs and debugging
| Command | What it does |
|---|---|
npx wrangler tail | Streams real-time logs from the live production worker — requests, console.log, and exceptions. |
npx wrangler tail --format pretty | Same, but formats output for easier reading in the terminal. |
npx wrangler tail --search "keyword" | Filters the live log stream to entries containing the keyword. |
npx wrangler deployments list | Lists all past deployments with timestamps and version IDs. |
Types and configuration
| Command | What it does |
|---|---|
npx wrangler types | Generates TypeScript types from your wrangler.jsonc bindings into worker-configuration.d.ts. Run after adding bindings. |
npx wrangler whoami | Shows the authenticated account name and account ID. |
npx wrangler --version | Shows the installed Wrangler version. |
npm install wrangler@latest | Updates Wrangler to the latest version. |
Quick reference — safe vs. production-affecting
| Safe — local only | Affects production — confirm first |
|---|---|
npm run dev | npm run deploy |
npx wrangler dev --local | npx wrangler dev --remote |
npx wrangler d1 execute … --local | npx wrangler d1 execute … --remote |
npx wrangler whoami | npx wrangler secret put/delete |
npx wrangler --version | npx wrangler rollback |
npx wrangler types | npx wrangler d1 create |
NPM vs. NPX
Both ship with Node.js, but they solve different problems: one manages dependencies your project keeps, the other runs tools you don't need to keep.
NPM Node Package Manager
- Installs and manages project dependencies.
- Downloads packages permanently into
node_modules.
Example: npm install lodash — downloaded permanently into your project's node_modules so you can import it into your code.
NPX Node Package eXecute
- Executes Node packages and CLI tools directly.
- Runs packages temporarily, without local or global storage.
Example: npx create-react-app my-app — looks for the tool locally, otherwise temporarily downloads the latest, runs it, then removes it. Your global space stays clean.
Troubleshooting notes
Compatibility date error
Wrangler fails to start with an error similar to the block below.
The Worker requires compatibility date "xxxx-yy-zz", but the newest
date supported by this server binary is "xxxx-yy-zz".
✘ [ERROR] The Workers runtime failed to start. There was likely a
problem with the workerd binary or your configuration.Fix: update the compatibility date in your project's Wrangler config file.
- Open
wrangler.json(orwrangler.toml) in your project directory. - Update the value:
"compatibility_date": "xxxx-yy-zz" - Save the file.
- Restart the local Worker session:
npm start
wrangler.toml vs. wrangler.json
| File | Description |
|---|---|
wrangler.toml | The original config format for Workers projects, written in TOML — its own syntax, distinct from (though visually similar to) YAML. Configures your application and references external components (bindings, environment variables, routes, and so on). |
wrangler.json | Serves the same purpose as wrangler.toml. Support for the .json extension was added for developers who prefer JSON over TOML. |
Critical fields in the Wrangler config file
| Field | Purpose |
|---|---|
name | The project name. Can be changed; determines your default *.workers.dev subdomain. |
main | The entry-point file for the project (e.g. src/index.ts). |