diff --git a/package.json b/package.json index f4800231797..f4843414b2a 100644 --- a/package.json +++ b/package.json @@ -175,7 +175,7 @@ "vite": "7.3.5", "vite-tsconfig-paths": "6.1.1", "vitest": "4.1.9", - "wrangler": "4.100.0", + "wrangler": "4.106.0", "zod": "4.4.3" }, "lint-staged": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 99760a7d96f..929afae353a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -46,7 +46,7 @@ importers: version: 5.0.0(@astrojs/starlight@0.40.0(@astrojs/markdown-satteri@0.2.1)(astro@6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.62.0)(tsx@4.22.4)(yaml@2.9.0))(typescript@5.9.3))(tailwindcss@4.1.4) '@base-ui/react': specifier: 1.5.0 - version: 1.5.0(@date-fns/tz@1.5.0)(@types/react@19.0.7)(date-fns@4.4.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + version: 1.5.0(@types/react@19.0.7)(date-fns@4.4.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@cloudflare/vitest-pool-workers': specifier: 0.16.15 version: 0.16.15(@cloudflare/workers-types@4.20260615.1)(@vitest/runner@4.1.9)(@vitest/snapshot@4.1.9)(vitest@4.1.9(@types/node@25.9.3)(happy-dom@20.10.3)(vite@7.3.5(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.22.4)(yaml@2.9.0))) @@ -420,8 +420,8 @@ importers: specifier: 4.1.9 version: 4.1.9(@types/node@25.9.3)(happy-dom@20.10.3)(vite@7.3.5(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.22.4)(yaml@2.9.0)) wrangler: - specifier: 4.100.0 - version: 4.100.0(@cloudflare/workers-types@4.20260615.1) + specifier: 4.106.0 + version: 4.106.0(@cloudflare/workers-types@4.20260615.1) zod: specifier: 4.4.3 version: 4.4.3 @@ -852,30 +852,60 @@ packages: cpu: [x64] os: [darwin] + '@cloudflare/workerd-darwin-64@1.20260630.1': + resolution: {integrity: sha512-oEVsD2NZtPAMaEvFeH2Y6N63yiFuOnPDKeAM+l8AkRbLAbFk462uWOq6/ZLn8ouY4P4coMkgsOPqcT1mkuzvzg==} + engines: {node: '>=16'} + cpu: [x64] + os: [darwin] + '@cloudflare/workerd-darwin-arm64@1.20260611.1': resolution: {integrity: sha512-yBbVXvbZyltR3I7NJdC4C4ItkItjZSiabcA/3HzEWOUQjLVKFqRh4so6ToHr70VCYh8VGeR8EDZL23igLhXqFQ==} engines: {node: '>=16'} cpu: [arm64] os: [darwin] + '@cloudflare/workerd-darwin-arm64@1.20260630.1': + resolution: {integrity: sha512-tar1vcQSzM+27Agrlv28BhtN1tIFKw2YHrzldEMyQJOJB/885TU8Z3oO1c/a9YOmsKABhD6I4dGFhsmXyrbK1g==} + engines: {node: '>=16'} + cpu: [arm64] + os: [darwin] + '@cloudflare/workerd-linux-64@1.20260611.1': resolution: {integrity: sha512-PfNjpxOlaIgZFYuhD7+neEEewCN2Ud993wEEN0fmbtSOax1AK53LGqmXUDvFhnbkHxJLFAxYCSNISW8QbzaAIg==} engines: {node: '>=16'} cpu: [x64] os: [linux] + '@cloudflare/workerd-linux-64@1.20260630.1': + resolution: {integrity: sha512-mhjIg91+ikWw5v9tY4BYO7N9vLOZBhn7EnVFvxCdxcpuUUFBKATxUYHUy1kkgYxnmiI6s93PRNbzBz1NpYQ3IQ==} + engines: {node: '>=16'} + cpu: [x64] + os: [linux] + '@cloudflare/workerd-linux-arm64@1.20260611.1': resolution: {integrity: sha512-GEp4XbuIKjlF8pakqXcUDJfKiJosD/Q7S83J0d+r+z9XIlYGfF3ntm08e2aiF5TFTwp3fnG4yMoPUAKNhNJpvQ==} engines: {node: '>=16'} cpu: [arm64] os: [linux] + '@cloudflare/workerd-linux-arm64@1.20260630.1': + resolution: {integrity: sha512-7g0iGvMCwGct+vE3FOKXtFWMAIGHzK2Ei9oALp44gXuL4lBcs3PPJISeTp5itquW2JwS1fw4Hnq7zrT7N/dgPw==} + engines: {node: '>=16'} + cpu: [arm64] + os: [linux] + '@cloudflare/workerd-windows-64@1.20260611.1': resolution: {integrity: sha512-S6JkS0kEbcCKs19RGqEPhjCRbP8GBkQwqYLp2fhBJtD/KTlwqLzOJ9E6PQ7gQKgWHtxy1NBG3oXarlNFRNU/dw==} engines: {node: '>=16'} cpu: [x64] os: [win32] + '@cloudflare/workerd-windows-64@1.20260630.1': + resolution: {integrity: sha512-J5KF9VF8yRpRBib/cPSuEp6iR9q3/cKgeDVhg1ZtuwpkzwnmCb+rxMF5WFLxAN8bI2x2FMG1v6o4vVFOGZ0fOQ==} + engines: {node: '>=16'} + cpu: [x64] + os: [win32] + '@cloudflare/workers-types@4.20260615.1': resolution: {integrity: sha512-fGOiTwoLj/8bU8mj3VAfa1EULx4ceZhDwnjvY+afDBlSXI9pvY7PE9t62rGEhJjbAOGd7i5WUDun0eZCWBDrzg==} @@ -887,9 +917,6 @@ packages: resolution: {integrity: sha512-kzyuwOAQnXJNLS9PSyrk0CWk35nWJW/zl/6KvnTBMFK65gm7U1/Z5BqjxeapjZCIhQcM/DsrEmcbRwDyXyXK4A==} engines: {node: '>=14'} - '@date-fns/tz@1.5.0': - resolution: {integrity: sha512-lwYN/vDPeNRULcepoE/LO2Pgx+7/RV+S9ARfbc9lr2DtGkOD7pAiruHvbR1RX3Qyf6ja47EWJDMsNK5vK08DJg==} - '@docsearch/css@3.9.0': resolution: {integrity: sha512-cQbnVbq0rrBwNAKegIac/t6a8nWoUAn8frnkLFW6YARaRmAQr5/Eoe6Ln2fqkUCZ40KpdrKbpSAmgrkviOxuWA==} @@ -4984,6 +5011,11 @@ packages: engines: {node: '>=22.0.0'} hasBin: true + miniflare@4.20260630.0: + resolution: {integrity: sha512-lyRplDrSJJWVpzSSQPBSQtNmUuxScCZyOOkXFs37uSbdTfWRDDmw6DyFKVS2s1eYtA/i4u2xR/0FyPIsTl/HJw==} + engines: {node: '>=22.0.0'} + hasBin: true + minimatch@10.2.5: resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==} engines: {node: 18 || 20 || >=22} @@ -6693,6 +6725,11 @@ packages: engines: {node: '>=16'} hasBin: true + workerd@1.20260630.1: + resolution: {integrity: sha512-7M0AA4l14hmPGtzQ5YPHyXosIKI/uz3TdcPHeiFDbgb7/0c8ECVMzIaodSV5bZIVhDHL0OlzqITAdPiwAr+dTg==} + engines: {node: '>=16'} + hasBin: true + wrangler@4.100.0: resolution: {integrity: sha512-dSQO7DO+mD6XDzkVWIWBoGLO3yw+lacWSc/KhFvd7pgfpth+kX98qb5SGRHZN8ACCDhhfwzDLXwB6qHsIHhfBg==} engines: {node: '>=22.0.0'} @@ -6703,6 +6740,16 @@ packages: '@cloudflare/workers-types': optional: true + wrangler@4.106.0: + resolution: {integrity: sha512-b6EVbsvbmAUY4bUQXT3+f8oFP8x+J5rEa5z3Akeh+6vyKiN4x8+PyZ53DPpnqdxhIihhq/a00Yq5chGJ19QXBQ==} + engines: {node: '>=22.0.0'} + hasBin: true + peerDependencies: + '@cloudflare/workers-types': ^4.20260630.1 + peerDependenciesMeta: + '@cloudflare/workers-types': + optional: true + wrap-ansi@10.0.0: resolution: {integrity: sha512-SGcvg80f0wUy2/fXES19feHMz8E0JoXv2uNgHOu4Dgi2OrCy1lqwFYEJz1BLbDI0exjPMe/ZdzZ/YpGECBG/aQ==} engines: {node: '>=20'} @@ -7350,7 +7397,7 @@ snapshots: '@babel/helper-string-parser': 7.29.7 '@babel/helper-validator-identifier': 7.29.7 - '@base-ui/react@1.5.0(@date-fns/tz@1.5.0)(@types/react@19.0.7)(date-fns@4.4.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@base-ui/react@1.5.0(@types/react@19.0.7)(date-fns@4.4.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: '@babel/runtime': 7.29.7 '@base-ui/utils': 0.2.9(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) @@ -7360,7 +7407,6 @@ snapshots: react-dom: 19.0.0(react@19.0.0) use-sync-external-store: 1.6.0(react@19.0.0) optionalDependencies: - '@date-fns/tz': 1.5.0 '@types/react': 19.0.7 date-fns: 4.4.0 @@ -7435,6 +7481,12 @@ snapshots: optionalDependencies: workerd: 1.20260611.1 + '@cloudflare/unenv-preset@2.16.1(unenv@2.0.0-rc.24)(workerd@1.20260630.1)': + dependencies: + unenv: 2.0.0-rc.24 + optionalDependencies: + workerd: 1.20260630.1 + '@cloudflare/vitest-pool-workers@0.16.15(@cloudflare/workers-types@4.20260615.1)(@vitest/runner@4.1.9)(@vitest/snapshot@4.1.9)(vitest@4.1.9(@types/node@25.9.3)(happy-dom@20.10.3)(vite@7.3.5(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.22.4)(yaml@2.9.0)))': dependencies: '@vitest/runner': 4.1.9 @@ -7453,18 +7505,33 @@ snapshots: '@cloudflare/workerd-darwin-64@1.20260611.1': optional: true + '@cloudflare/workerd-darwin-64@1.20260630.1': + optional: true + '@cloudflare/workerd-darwin-arm64@1.20260611.1': optional: true + '@cloudflare/workerd-darwin-arm64@1.20260630.1': + optional: true + '@cloudflare/workerd-linux-64@1.20260611.1': optional: true + '@cloudflare/workerd-linux-64@1.20260630.1': + optional: true + '@cloudflare/workerd-linux-arm64@1.20260611.1': optional: true + '@cloudflare/workerd-linux-arm64@1.20260630.1': + optional: true + '@cloudflare/workerd-windows-64@1.20260611.1': optional: true + '@cloudflare/workerd-windows-64@1.20260630.1': + optional: true + '@cloudflare/workers-types@4.20260615.1': {} '@cspotcode/source-map-support@0.8.1': @@ -7473,9 +7540,6 @@ snapshots: '@ctrl/tinycolor@4.2.0': {} - '@date-fns/tz@1.5.0': - optional: true - '@docsearch/css@3.9.0': {} '@docsearch/js@3.9.0(@algolia/client-search@5.54.1)(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(search-insights@2.17.3)': @@ -12144,6 +12208,18 @@ snapshots: - bufferutil - utf-8-validate + miniflare@4.20260630.0: + dependencies: + '@cspotcode/source-map-support': 0.8.1 + sharp: 0.34.5 + undici: 7.28.0 + workerd: 1.20260630.1 + ws: 8.21.0 + youch: 4.1.0-beta.10 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + minimatch@10.2.5: dependencies: brace-expansion: 5.0.6 @@ -14151,6 +14227,14 @@ snapshots: '@cloudflare/workerd-linux-arm64': 1.20260611.1 '@cloudflare/workerd-windows-64': 1.20260611.1 + workerd@1.20260630.1: + optionalDependencies: + '@cloudflare/workerd-darwin-64': 1.20260630.1 + '@cloudflare/workerd-darwin-arm64': 1.20260630.1 + '@cloudflare/workerd-linux-64': 1.20260630.1 + '@cloudflare/workerd-linux-arm64': 1.20260630.1 + '@cloudflare/workerd-windows-64': 1.20260630.1 + wrangler@4.100.0(@cloudflare/workers-types@4.20260615.1): dependencies: '@cloudflare/kv-asset-handler': 0.5.0 @@ -14168,6 +14252,23 @@ snapshots: - bufferutil - utf-8-validate + wrangler@4.106.0(@cloudflare/workers-types@4.20260615.1): + dependencies: + '@cloudflare/kv-asset-handler': 0.5.0 + '@cloudflare/unenv-preset': 2.16.1(unenv@2.0.0-rc.24)(workerd@1.20260630.1) + blake3-wasm: 2.1.5 + esbuild: 0.28.1 + miniflare: 4.20260630.0 + path-to-regexp: 6.3.0 + unenv: 2.0.0-rc.24 + workerd: 1.20260630.1 + optionalDependencies: + '@cloudflare/workers-types': 4.20260615.1 + fsevents: 2.3.3 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + wrap-ansi@10.0.0: dependencies: ansi-styles: 6.2.3 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index e66f5d67323..bab078cb37b 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -6,6 +6,13 @@ minimumReleaseAge: 1440 # age guard so freshly-cut versions install without a 24h wait. minimumReleaseAgeExclude: - nimbus-docs + # First-party Cloudflare packages, published frequently. The docs site bumps + # Wrangler often to regenerate the autogenerated command reference, so exempt + # it (and its miniflare dependency) from the 24h wait. + - wrangler + - miniflare + - workerd + - "@cloudflare/workers-types" # @astrojs/mdx's @astrojs/markdown-satteri peer is optional and only engages when # markdown.processor is Sätteri (the Nimbus target, via nimbus-docs's pinned mdx diff --git a/src/content/changelog/workers/2026-07-02-wrangler-auth-profiles.mdx b/src/content/changelog/workers/2026-07-02-wrangler-auth-profiles.mdx new file mode 100644 index 00000000000..b513c5a7f3e --- /dev/null +++ b/src/content/changelog/workers/2026-07-02-wrangler-auth-profiles.mdx @@ -0,0 +1,32 @@ +--- +title: Work across multiple accounts with Wrangler auth profiles +description: Maintain separate logins and switch between Cloudflare accounts per project, without re-running wrangler login. +products: + - workers +date: 2026-07-02 +--- + +[Wrangler CLI](/workers/wrangler/) now supports auth profiles: named logins that you scope to specific Cloudflare accounts and switch between automatically, based on the directory you are working in. + +A profile is a named OAuth login bound to a directory. Commands run in that directory, and its subdirectories, use the matching account — so you can move between accounts without re-running `wrangler login`. + +Use profiles to keep a separate login for each client when working at an agency, or to separate staging and production into different accounts. Pair a profile with an `account_id` in your [Wrangler configuration file](/workers/wrangler/configuration/) so a command cannot reach the wrong account. + +```sh +# Create a profile for each account, choosing which accounts it can reach +wrangler auth create client-a +wrangler auth activate client-a ~/clients/client-a + +wrangler auth create client-b +wrangler auth activate client-b ~/clients/client-b +``` + +Use the `--profile` flag to run a single command with a specific profile: + +```sh +wrangler deploy --profile personal +``` + +In CI and other automated environments, `CLOUDFLARE_API_TOKEN` still takes precedence over all profiles. + +For setup, the resolution order, and the full command reference, refer to [Authentication profiles](/workers/wrangler/profiles/). diff --git a/src/content/docs/workers/wrangler/commands/general.mdx b/src/content/docs/workers/wrangler/commands/general.mdx index 245e499f320..d5393513f22 100644 --- a/src/content/docs/workers/wrangler/commands/general.mdx +++ b/src/content/docs/workers/wrangler/commands/general.mdx @@ -136,6 +136,8 @@ If you are using `CLOUDFLARE_API_TOKEN` instead of OAuth, and you can logout by ## `auth` +Manage authentication, including named [authentication profiles](/workers/wrangler/profiles/) for working across multiple accounts. + ### `auth token` Retrieve your current authentication token or credentials for use with other tools and scripts. @@ -170,6 +172,16 @@ An error is returned if no authentication method is available, or if API key/ema + + + + + + + + + + --- diff --git a/src/content/docs/workers/wrangler/profiles.mdx b/src/content/docs/workers/wrangler/profiles.mdx new file mode 100644 index 00000000000..c5eb0ef1701 --- /dev/null +++ b/src/content/docs/workers/wrangler/profiles.mdx @@ -0,0 +1,170 @@ +--- +pcx_content_type: concept +title: Authentication profiles +description: Maintain separate logins and switch accounts per directory. +products: + - workers +--- + +import { Steps, WranglerConfig } from "~/components"; + +Wrangler authenticates as one user at a time. A profile is a named OAuth login that you scope to a chosen set of accounts can bind to a directory. + +Use profiles to switch between accounts for different projects without re-running [`wrangler login`](/workers/wrangler/commands/general/#login). Profiles live under [`wrangler auth`](/workers/wrangler/commands/general/#auth). + +:::note +Authentication profiles are in beta. The commands and their behavior may change. +::: + +## When to use profiles + +Use profiles when you work across more than one Cloudflare account on the same machine: + +- **Agency and client work** — keep a separate login for each client account and bind it to that client's project directory. Commands run in each directory use the matching profile automatically. +- **Account-separated environments** — keep staging and production in different accounts, then bind a profile to each. Pair a profile with an `account_id` in your [Wrangler configuration file](/workers/wrangler/configuration/) so a command cannot reach the wrong account. + +## How profiles work + +A profile combines two things: + +- A login, created through OAuth. During the OAuth flow you choose which accounts the profile may reach. One profile can hold access to several accounts that your user holds. +- A directory binding. When you activate a profile in a directory, that directory and its subdirectories use the profile. + +### Resolution order + +For each command, Wrangler selects a profile in this order, highest priority first: + + +1. The [`CLOUDFLARE_API_TOKEN`](/workers/wrangler/system-environment-variables/#supported-environment-variables) environment variable. When set, it overrides all profiles. +2. The [`--profile`](#switch-profiles-for-a-single-command) flag, which applies to a single command run. +3. The nearest activated ancestor directory. Wrangler resolves from the directory containing the configuration file when you pass `--config`, otherwise from the working directory. +4. The default profile, managed by `wrangler login` and `wrangler logout`. + + +### Account selection + +Within the resolved profile, Wrangler selects the target account in this order: + + +1. The `account_id` in your [Wrangler configuration file](/workers/wrangler/configuration/#inheritable-keys), or the [`CLOUDFLARE_ACCOUNT_ID`](/workers/wrangler/system-environment-variables/#supported-environment-variables) environment variable. +2. Otherwise, the account selected for the profile during login. + + +If a command targets an account that the active profile cannot reach, Wrangler fails with an error that names the account and profile. Wrangler does not fall back to another account. + +## Create a profile + +Run [`wrangler auth create`](/workers/wrangler/commands/general/#auth-create) with a name. Wrangler starts the OAuth flow, where you choose which accounts the profile may reach. + +```sh +wrangler auth create work +``` + +Run the command again with the same name to re-authenticate an existing profile, for example after its token expires. + +## Activate a profile in a directory + +Run [`wrangler auth activate`](/workers/wrangler/commands/general/#auth-activate) to bind a profile to a directory. The binding applies to that directory and its subdirectories. The directory defaults to the current working directory. + +```sh +wrangler auth activate work ~/projects/work +``` + +A subdirectory can override the profile bound above it by activating a different profile. + +## Work across multiple client accounts + +This example sets up one profile per client for agency work. + + +1. Create a profile for the first client. During the OAuth flow, choose the accounts this profile may reach. + + ```sh + wrangler auth create client-a + ``` + +2. Bind the profile to the client's project directory. + + ```sh + wrangler auth activate client-a ~/clients/client-a + ``` + +3. Repeat for the second client. + + ```sh + wrangler auth create client-b + wrangler auth activate client-b ~/clients/client-b + ``` + + + +Commands run in `~/clients/client-a` now use the `client-a` profile, and commands in `~/clients/client-b` use the `client-b` profile. You do not need to log in again to switch between them. + +## Separate staging and production accounts + +When staging and production live in different accounts, bind a profile to each environment's directory and pin the account in each project's configuration. The `account_id` acts as a failsafe, so a command cannot deploy to the wrong account even if the profile can reach both. + + +1. Create and activate a profile for each environment. + + ```sh + wrangler auth create staging + wrangler auth activate staging ~/projects/staging + + wrangler auth create production + wrangler auth activate production ~/projects/production + ``` + +2. Set the matching `account_id` in each project's [Wrangler configuration file](/workers/wrangler/configuration/). + + + + ```toml title="~/projects/production/wrangler.toml" + name = "my-worker" + account_id = "" + ``` + + + + + +## Switch profiles for a single command + +Use the `--profile` flag to run one command with a specific profile, without changing any directory binding. + +```sh +wrangler deploy --profile staging +``` + +The `--profile` flag is not supported by the `auth`, `login`, `logout`, and `whoami` commands. + +## List profiles + +Run [`wrangler auth list`](/workers/wrangler/commands/general/#auth-list) to see every profile and the directories bound to it. + +```sh +wrangler auth list +``` + +## Remove a binding or a profile + +To stop a directory from using a profile, run [`wrangler auth deactivate`](/workers/wrangler/commands/general/#auth-deactivate) in that directory. The directory returns to the profile bound above it, or to the default profile. + +```sh +wrangler auth deactivate ~/projects/staging +``` + +To remove a profile and all of its directory bindings, run [`wrangler auth delete`](/workers/wrangler/commands/general/#auth-delete). + +```sh +wrangler auth delete staging +``` + +## Profiles and environment variables + +Profiles are a local-machine convenience. They do not apply in CI, containers, or other automated environments, which authenticate per environment with [`CLOUDFLARE_API_TOKEN`](/workers/wrangler/system-environment-variables/#supported-environment-variables). For more information, refer to [Running Wrangler in CI/CD](/workers/ci-cd/). + +Two rules apply when environment variables are present: + +- When `CLOUDFLARE_API_TOKEN` is set, Wrangler uses it instead of any profile. You cannot create, activate, deactivate, or delete profiles while it is set. +- `CLOUDFLARE_ACCOUNT_ID` and an `account_id` in your Wrangler configuration file are always respected, including within an active profile.