> This page is for Home.

> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://developers.webflow.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://developers.webflow.com/_mcp/server.

# v2.8.0: `webflow apps`, the canonical namespace for Webflow Cloud

> A new webflow apps command family covers the full Webflow Cloud app lifecycle — init/deploy, environments, deployments, logs, and environment variables — with --json and --dry-run on every write, built for CI and AI agents as much as for humans.

v2.8.0 introduces `webflow apps`, the new canonical command namespace for managing Webflow Cloud apps. It replaces the piecemeal `webflow cloud` commands with one consistent surface across the whole app lifecycle, designed so a CI job or an AI agent can drive it end-to-end without scraping human-oriented output: structured `--json` on read commands, `--dry-run` previews on every write, and predictable exit codes throughout. Reads also retry transient rate limits (`429`) automatically with bounded backoff, so a busy CI runner doesn't need its own retry loop.

`webflow cloud init` and `webflow cloud deploy` keep working unchanged — they now print a one-time deprecation notice pointing at the `apps` equivalents.

An app is standalone by default — it gets its own subdomain and isn't tied to a Webflow site. Attaching to an existing site (mounted at a path, alongside a Designer-built site) is fully supported too; it's just one additional flag away.

### App lifecycle: `apps init` / `apps deploy`

```bash
# Standalone — the default. Owns its own subdomain, no Webflow site involved.
webflow apps init -n my-app -f astro --new -w <workspaceId>
webflow apps deploy -e main
```

Once `webflow.json` has an `app_id`, subsequent `apps deploy` calls need no flags at all — it's the standalone path that gets simpler over time, since there's no site or mount path to keep in sync.

`apps deploy` also takes `--dry-run` and `--json`, same as every other write in this namespace:

```bash
webflow apps deploy -e main --dry-run
webflow apps deploy -e main --json
```

`--dry-run` resolves everything from flags, `WEBFLOW_APP_ID`, and `webflow.json` — no network calls, no prompts, no changes — and reports which of `create` / `deploy` / `select` the real run would take. `--json` suppresses the build/upload progress output and emits a single document: `{appId, environmentId, deploymentId, deployUrl}` on success, an error document on failure, or the dry-run plan when combined with `--dry-run`.

Because `--json` means nobody is at the keyboard, it never opens a picker. A real deploy with `--json` therefore requires `--environment` and `--mount`, plus an identity it can resolve without asking — `--site-id`, `--workspace-id`, `WEBFLOW_SITE_ID`, or `siteId` in `webflow.json`. An invocation that would have prompted is refused up front with the flag to pass. A dry run needs none of these.

When creating a standalone app, `--access <everyone|restricted>` sets its site-specific access on `apps deploy` and on `apps init --import --new`. It is not accepted on the deprecated `webflow cloud` commands, and it is refused when the deploy targets an existing app.

Attaching to an existing Webflow site instead just adds `--site-id` and a `--mount` path at init:

```bash
# Site-attached — mounted at a path on an existing Webflow site.
webflow apps init -n my-app -f astro -s <siteId> -m /app
webflow apps deploy -e main --site-id <siteId> --mount /app
```

`apps init` also supports creating an app directly from an existing GitHub repository, either standalone or attached to a site:

```bash
webflow apps init --import https://github.com/<owner>/<repo> --new --dry-run
webflow apps init --import https://github.com/<owner>/<repo> --site-id <siteId> --mount /app --dry-run
webflow apps init --import https://github.com/<owner>/<repo> --new --skip-clone
webflow apps init --import https://github.com/<owner>/<repo> --branch staging --new --idempotency-key $GITHUB_RUN_ID-$REPOSITORY
```

The Webflow GitHub App must be installed on the repository and connected to your workspace. `--dry-run` previews the app that would be created; `--branch` picks which branch to build (defaults to the repository's default branch); `--skip-clone` creates the app from the remote repository without cloning it into a local directory. `--idempotency-key` is required for non-interactive runs (CI, `--no-input`) — reuse a retry-stable key unique to the repository and target so a retry replays the original app instead of creating a second one.

### Link an existing app: `apps link`

```bash
webflow apps link <appId> --workspace-id <workspaceId> --dry-run
```

Points the current directory at an app and environment that already exist by writing the resolved IDs into `webflow.json`. It only verifies the app — it doesn't create or deploy anything, so it's the fastest way to get a checked-out repo working with `apps deploy` / `apps env-vars` / `apps logs` against an app someone else created. A workspace ID is persisted only when `--workspace-id` is passed explicitly, since it can't be derived or verified from the app itself. Use `--dry-run` to preview.

### Inspect apps: `apps list` / `apps get` / `apps domains`

```bash
webflow apps list --json
webflow apps get <appId> --fields id,name,siteId,sourceUrl --json
webflow apps domains <appId>
```

`list` returns every app the token can see — standalone and site-attached alike — and optionally narrows with an exact `--site` or `--name`, or a case-insensitive substring `--q`; combine `--site` and `--name` to resolve to at most one app. All three support `--fields` to project columns and `--json` for machine-readable output.

### Manage apps: `apps update` / `apps delete`

```bash
webflow apps update <appId> --name "New name" --description "Internal tools dashboard" --dry-run --json
webflow apps update <appId> --github-source https://github.com/<owner>/<repo> --json
webflow apps delete <appId> --dry-run --json
webflow apps delete <appId> --yes --json
```

Update an app's name, description, and/or GitHub source (at least one of `--name` / `--description` / `--github-source` is required). `--github-source` attaches a repository to an app that has none, or repoints one that already has a different repo — it doesn't deploy on its own, so follow it with `apps deployments trigger`. `apps delete` deletes (archives) an app outright; it refuses to run non-interactively without `--yes` (a safe `--dry-run` preview is exempt).

Both commands preview with `--dry-run` before making any change, and both support `--json` on every path:

* `update --json` prints the plan (only the keys actually being changed, plus `dryRun: true`) on a dry run, and the full updated app object on a real run.
* `delete --json` prints one document shape on both the dry run and the real run — `{ appId, name, action: "archive" | "hard_delete", siteId, siteName, permanent, dryRun, message }` — so a caller can parse the same fields either way; `message` is `null` until the delete actually happens.

### Environments: `apps environments list/create/update/delete`

```bash
webflow apps environments list <appId> --branch main --json
webflow apps environments create <appId> --branch feature/checkout --mount /checkout --dry-run
webflow apps environments update <appId> <envId> --branch main --dry-run
webflow apps environments delete <appId> <envId> --dry-run
```

`list` filters by an exact `--branch` or a substring `--q` on branch name. `create` provisions a new environment bound to a branch and served at a mount path — it starts empty; run `apps deployments trigger` to build it. `update` changes an environment's branch and/or mount (at least one is required) but doesn't deploy the change itself. `delete` removes an environment. All three writes support `--dry-run`, and resolve the app/environment from positional args, `WEBFLOW_APP_ID` / `WEBFLOW_APP_ENVIRONMENT_ID`, `webflow.json`, or an interactive picker.

### Deployments: `apps deployments list/get/redeploy/trigger`

```bash
webflow apps deployments list --status failed --json
webflow apps deployments get <deploymentId> --wait --interval 10 --timeout 300 --json
webflow apps deployments trigger --wait --json
webflow apps deployments redeploy <deploymentId> --idempotency-key $GITHUB_RUN_ID --wait --json
```

`list --status` filters on an exact status (`success`, `failed`, `starting`, `building`, `deploying`, `canceled`, `unstaged`). `get --wait` polls until the deployment reaches a terminal status and exits `0`/`1` accordingly — built for CI gating; `--interval` and `--timeout` tune the poll (floored at 5s, capped at 30min). The default polling interval for deployment waits is now 20 seconds, up from 5.

`trigger` builds a GitHub-connected environment's current HEAD on demand; `redeploy` re-runs a past deployment at the same commit, the rollback path. Both require a GitHub-connected app (not eligible for apps deployed from local files via `apps deploy`) and now also take `--wait` (with the same `--interval`/`--timeout`): since enqueuing a build only returns a 202 with no deployment ID to poll, `--wait` identifies the new deployment itself and then blocks on it exactly like `deployments get --wait` — so a CI job can trigger a build and gate on its outcome in one command. All three writes support `--dry-run`.

### Logs: `apps logs build` / `apps logs runtime`

```bash
webflow apps logs build <deploymentId> --since <iso> --q <text>
webflow apps logs runtime [envId] --limit 200 --json
```

Both support `--fields`, `--json`, and cursor-based pagination via `--cursor`.

### Environment variables: `apps env-vars list/set/delete/import`

The headline addition this release: full, non-interactive management of Cloud app environment variables, so secrets no longer require a trip to the dashboard.

```bash
webflow apps env-vars list --fields key,isSecret --json
webflow apps env-vars list --q API --json
printf %s "$VALUE" | webflow apps env-vars set API_KEY --secret
webflow apps env-vars delete OLD_KEY --dry-run
webflow apps env-vars import .env --secret --dry-run
```

* `--app-id` / `--environment-id` default from `webflow.json` (`cloud.app_id` / `cloud.environment_id`) when present — as shown above — so most invocations inside a project directory need neither flag. Pass them explicitly (`--app-id <id> --environment-id <id>`) to target a different app, for example from a shared CI runner.
* `list` also takes an exact `--key` or a case-insensitive substring `--q`, same filtering pattern as `apps list` and `apps environments list`.
* `set <key> [value]` takes the value three ways, safest first: piped stdin (shown above — works in CI with no TTY), an interactive prompt (masked for secrets) if you omit the value entirely, or a positional argument. A positional secret still works but prints a warning, since it lands in your shell history and process list — stdin or the prompt avoid that.
* `--secret` marks a variable encrypted. **Secret values are never echoed back** — `set` on a secret confirms only that it was written, and `list` never returns a secret's value — it comes back masked. Non-secret values are hidden from the default output too, and shown only if you ask for them with `--fields value` or `--json`.
* `import <file>` bulk-loads a `.env` (or any `KEY=value`) file in one call instead of setting variables one by one. `--dry-run` parses and previews the resulting key set — secret values shown redacted — without making any API calls or writing anything.
* Every write command (`set`, `delete`, `import`) supports `--dry-run` and `--json`.

### Exit codes

Exit codes are now more specific, so scripts and agents can branch on why a command failed:

| Code  | Meaning                                                                                                                          |
| ----- | -------------------------------------------------------------------------------------------------------------------------------- |
| `0`   | Success                                                                                                                          |
| `1`   | Any other failure                                                                                                                |
| `2`   | A user-recoverable error you can fix yourself — bad input, a missing required flag, a resource locked by another process         |
| `3`   | An auth or permission failure — the API rejected the token (401/403), or the CLI has no valid session. Run `webflow auth login`. |
| `4`   | Rate limited                                                                                                                     |
| `5`   | A transient failure (5xx, 408, network) that exhausted its retries                                                               |
| `130` | Ctrl-C                                                                                                                           |

A script that only checks `$? -ne 0` sees no difference. One that checks `$? -eq 1` to mean "any failure" should switch to `$? -ne 0`.

With `--json`, error output also gains optional fields when available: `httpStatus`, `retryable`, `retryAfterMs`, `attempts`, `requestId`, and `authError`.

### Sign-in scope and session file

Logging in now requests one additional OAuth scope, `cloud_apps:read`, needed to read your Webflow Cloud apps. `webflow auth login` does nothing when a session already exists, so if you signed in before this release, run it once with `--force` to get a token that includes the new scope:

```bash
webflow auth login --force
```

`webflow auth login` and `logout` now write a v4 `auth.json` that separates the persistent default region from the stored session. An older CLI cannot read this shape — after downgrading, run `webflow auth login` again. A corrupt or unrecognized-version file now fails with a clear error naming the file, and `webflow auth logout` resets it.

On `@next` (beta) builds only, commands now honor the region you logged into. Stable `@latest` builds still route to the US region.

### Also in this release

* `apps init --site-id <id> --no-input` now correctly attaches the new app to the existing site and runs the DevLink export, instead of silently falling back to a standalone app without one.
* The `publicUrl` field on an environment (`apps environments list/create/update`) replaces the old `deployUrl` field name.
* Webflow Cloud Astro builds now keep the `build.*` options from your `astro.config.*` (for example `build.format` and `build.inlineStylesheets`) instead of discarding them. `build.assetsPrefix` is still owned by Webflow Cloud. `build.client`, `build.server`, and `build.serverEntry` are ignored with a build-log warning, because relocating Astro's output would break packaging.
* `webflow cloud deploy` no longer modifies your project's source `webflow.json` with deployment-generated metadata.
* `webflow skills install` now prints the exact command needed to resolve a blocked destination.
* `@webflow/react` 2.4.0 fixes a React 19 prerender abort race.
* `@webflow/functions` 2.4.0 extends `FunctionConfig` with an optional `access` (`public`).

## Upgrading

```bash
npm install -g @webflow/webflow-cli@latest
```