Webflow Cloud: Deployments and Environments

This content was generated with the assistance of AI and should be verified against the official Webflow documentation before being relied on in production.

This sub-section’s Webflow bibliography lists the reference material consulted while preparing these pages.

This page describes how code reaches a running Webflow Cloud app and how that app is configured, observed and rolled back, as it was on 2026-10-28. The facts were checked against the Environments and Deployments pages of the Webflow Cloud documentation, the GitHub App permissions page, the CLI command reference and agent-workflows pages, and the developer changelog on developers.webflow.com. Webflow Cloud is a paid capability whose availability depends on the Workspace and Site plan tier; plans are named by tier only on this page and never by price, and the plan matrix is in Plans, Workspaces, Seats and Roles. The CLI examples use @webflow/webflow-cli 2.15.0 on the next channel, which requires Node.js 22.13.0 or later; the apps command family used below does not exist on the stable channel (see Webflow CLI).

What Webflow Cloud is, how a mount path sits in front of a Webflow site, and how to create the app are covered in Webflow Cloud; the SQLite, key-value and object storage that an environment provisions are in Webflow Cloud: Storage. This page is about the operating model between those two: environments, deployments, variables, logs and the pipelines that drive them.

The running example is Visit Planner, the Next.js app that Fernbrook Gardens mounts at /planner to let visitors assemble a day itinerary of plants, zones and events. The garden’s developer keeps two environments, production (branch main, mounted at /planner) and staging (branch staging, mounted at /planner-staging), and wants every merge to reach the right one without manual steps.

The model in one picture

Three nouns carry the whole system.

  • An app is the unit you create in Webflow Cloud. It is attached to a Webflow site or stands alone in a Workspace, and it points at one GitHub repository when it is connected to Git.

  • An environment is an isolated container in which the app runs. It tracks exactly one branch and owns exactly one mount path. Variables, secrets and provisioned storage belong to the environment, not to the app.

  • A deployment is one build-and-release attempt of one commit into one environment. A deployment either succeeds and becomes what the environment serves, or fails and leaves the previous successful deployment in place.

flowchart LR DEV["Developer"] -->|push| BRANCH["Git branch"] BRANCH -->|GitHub App| DEPLOY["Deployment"] CLI["webflow apps deploy or trigger"] --> DEPLOY BUTTON["Deploy latest build button"] --> DEPLOY DEPLOY --> BUILD["Clone, detect, build"] BUILD -->|success| ENV["Environment serves the new build"] BUILD -->|failure| KEEP["Environment keeps the last good build"] VARS["Variables and secrets"] --> BUILD VARS --> ENV ENV --> LOGS["Build logs and runtime logs"]

Publishing the Webflow site does not trigger a Webflow Cloud deployment, and a Webflow Cloud deployment does not publish the site. The two pipelines are independent; the only bridge is the optional --auto-publish flag of apps deploy, described below. The consequence for a site-attached app such as Visit Planner is that a content editor can publish the garden’s Webflow pages at any time without touching the app, and the developer can deploy the app without republishing the site.

Environments

What an environment is

An environment is an isolated container where your app is deployed. Typical setups are production, staging and development, each tracking a different GitHub branch. An environment updates automatically when a deployment to it succeeds, with zero downtime, and if a deployment fails the environment keeps serving its last successful deployment. Every push to the tracked branch triggers a deployment.

Property Meaning

Branch

The one Git branch whose pushes deploy to this environment.

Mount path

The URL path under the Webflow domain that routes traffic to this environment, such as /planner. It must be unique within the app.

Variables and secrets

The configuration of this environment alone. Another environment of the same app has its own set.

Bindings

The storage resources declared in wrangler.json are provisioned separately for each environment during deployment, so staging and production never share a database.

Deployments

The history of builds for this environment.

Creating, editing and deleting

In the Dashboard, open the Environments view, choose Create New Environment, pick a branch, set a mount path and confirm. The same operation from a terminal is apps environments create, which requires both --branch and --mount:

webflow apps environments create REPLACE_WITH_APP_ID \
  --branch staging --mount /planner-staging \
  --idempotency-key "fernbrook-create-staging" --dry-run

--dry-run previews the change without making it; drop it to create the environment. An environment created from the CLI starts empty, so it has nothing to serve until a deployment is triggered with apps deployments trigger. --idempotency-key accepts a non-empty string of printable ASCII characters and makes a retried create safe.

Editing an environment, through the ellipsis menu in the Dashboard or apps environments update, can change the branch or the mount path. Two details matter:

  • Changing the branch does not rebuild. The environment keeps serving its current build until a new deployment is triggered.

  • Changing the mount path needs a redeploy. References to the path are baked into the build as the base path and asset prefix, so the new path takes effect only after a fresh deployment.

Deleting an environment permanently removes all of its deployments. It does not delete the GitHub branch, and deleting a branch does not delete the environment, so both must be cleaned up separately. Unpublishing an app from a domain means deleting its environment; deleting the app resources alone is not enough. Without a terminal and without --yes, apps environments delete refuses to run, which protects a script from deleting by accident.

Mount paths and route conflicts

The mount path becomes the base path of the framework at build time. Where a Webflow page and a Webflow Cloud route share a path, the Webflow Cloud application route takes precedence, so pick a dedicated path such as /planner rather than reusing the path of an existing page. The rules for assets, fetch() calls and the Cache-Control override are in Webflow Cloud. Because staging and production have different mount paths, code must read the path rather than hard-code it. In Next.js the mount path is exposed through the NEXT_PUBLIC_BASE_PATH variable, in Astro through BASE_URL and ASSETS_PREFIX:

// app/lib/api.ts in Visit Planner
const baseUrl = process.env.NEXT_PUBLIC_BASE_PATH ?? '';

export async function loadItinerary(id: string) {
  const response = await fetch(`${baseUrl}/api/itineraries/${id}`);
  return response.json();
}

Who can see an environment

Anyone who has the mount path URL can open that environment, so a staging environment on a public domain is public unless the app itself protects it. Anyone with access to the Webflow site can view its apps and environments in the Dashboard. Treat a staging mount path as unlisted rather than private, and put an authentication check in the app if it must not be seen. Sites that need a login for the whole domain should look at Password Protection and Site Search and at Reverse Proxy and Custom Hosting.

Connecting GitHub

Webflow Cloud deploys from GitHub. Bitbucket and GitLab are not supported as sources, so a repository hosted elsewhere must be mirrored to GitHub or deployed from the CLI.

The deploy wizard

The first connection is made in the setup wizard:

  1. Open Webflow Cloud and select the app.

  2. Choose Log in to GitHub.

  3. Connect one or more repositories to the Webflow Cloud GitHub App.

  4. Select a repository.

  5. Create or select an environment.

  6. Choose the branch to deploy to that environment.

If the GitHub account can reach more than 100 repositories, the repository list may not load; paste the repository link into the GitHub repository field instead. If the connection fails, check that you have admin access to the repository, review the permissions granted to the App, and try disconnecting and reconnecting.

What the GitHub App can do

The App asks for a small set of permissions, and it is worth reading them before an organisation approves it.

Permission Level Purpose

Contents

Write (includes read)

Reads the repository to build and deploy. Write is used only for the one-time initial commit when a starter template is pushed into a new repository.

Metadata

Read

Checks that the App is installed on a repository and looks up basic repository details.

Administration

Write

Required by the installation check before the deploy wizard continues. It is not used to delete repositories or change their settings.

user:email (OAuth)

Read

Identifies the GitHub account during login and account linking; it grants no repository access.

Two credentials are involved: the App installation token reads repositories and makes the initial template push, and the user’s own OAuth token creates new repositories. Ongoing deployments never edit your code. Access is managed on GitHub: install or update the App to choose accounts, organisations and repositories, review or uninstall it on the installations page, or disconnect GitHub from the wizard or the app settings and authorise again with a narrower repository set when an organisation policy requires it. When deployments stop starting, the first thing to check is that the App still has access to the repository.

Deployments

What starts a deployment

  • A push to the branch tracked by an environment, through GitHub continuous deployment.

  • The Deploy latest build button in the environments Dashboard.

  • webflow cloud deploy or webflow apps deploy from a terminal.

  • webflow apps deployments trigger, which builds the current head of the environment’s branch on demand.

  • webflow apps deployments redeploy, which re-runs an earlier deployment at its commit.

Publishing the Webflow site is not on the list, as explained above.

What the pipeline does

Each deployment runs the same steps in order: clone the repository, detect the framework from the project files or from webflow.json, validate that the deployment path is supported, install dependencies and adapters when needed, generate the required configuration, build the framework app (static apps skip the build), then collect the output and release it to the environment. Webflow Cloud merges its own settings over yours at build time: the adapter, base path, asset handling, Node.js compatibility and observability are set by the platform, so do not commit them in framework configuration.

If the framework is not detected, confirm that the framework dependency is in package.json at a supported version, or declare it in webflow.json under cloud.framework. For a monorepo, set the app path in the environment settings (or pass --directory to apps deploy).

Statuses

The Dashboard shows five statuses: building, deploying, success, cancelled and failure. The CLI reports the more detailed set starting, building and deploying while a deployment is in flight, and success, failed, canceled and unstaged once it has finished. Each history entry shows the date and time, the build and deployment durations and the logs. If a new deployment is not visible, refresh the Dashboard. A preview is available only for the most recent successful deployment of each environment.

Listing and inspecting from the CLI

webflow apps deployments list --limit 5 --json
webflow apps deployments get REPLACE_WITH_DEPLOYMENT_ID --wait --interval 10 --timeout 300

list returns the most recent deployments first, 20 by default, with the fields id, status, sourceType, commitHash and buildStartedAt. With --json the output is an envelope with a deployments array and a nextCursor, not a bare array, so a script reads .deployments[0].id for the newest one. get --wait polls until a terminal status: the interval defaults to 5 seconds and cannot go below that, and the timeout defaults to 600 seconds and is capped at 1800. The exit code is 0 only for success; every other terminal status and a timeout both exit 1, so a script that must tell a failed build from one that is merely slow reads the reported status as well as the exit code.

Deploying from a terminal

webflow apps deploy builds and releases from the local directory. It is the route for repositories that are not on GitHub, for first deployments of a new app, and for quick checks. The flags that matter:

Flag Effect

-e, --environment

Environment to deploy to; it is created when it does not exist.

-m, --mount

Mount path. Always pass it with --no-input; if it is omitted the app is deployed at the root of the domain.

-n, --app-name

Name used on the first deployment.

-d, --directory

Subdirectory of the app, for monorepos.

--description

Free-text description of the deployment.

--skip-mount-path-check

Skips the check of the mount path.

--auto-publish

Publishes the Webflow site after the deployment finishes.

-s, --site-id or -w, --workspace-id

Target a site-attached app or a standalone project app. The two are mutually exclusive and fail before any call to the backend.

-a, --app-id and -f, --framework

Override the app from webflow.json; the framework is nextjs or astro and is written back to the manifest.

The deploy prompts appear unless both --mount and --environment are given, so --no-input alone can hang in CI. The target is resolved in a fixed order: --site-id, --workspace-id, WEBFLOW_SITE_ID, the siteId key of webflow.json, WEBFLOW_WORKSPACE_ID, cloud.workspace_id, and then an error under --no-input or a picker otherwise. A stale WEBFLOW_SITE_ID therefore overrides a project-app manifest, so pass explicit flags in scripts.

webflow apps deploy --no-input \
  --site-id REPLACE_WITH_SITE_ID \
  --mount /planner --environment production \
  --description "Visit Planner: itinerary sharing"

On the stable CLI channel the same job is webflow cloud deploy, which is an alias of apps deploy, and webflow cloud init is the alias of apps init; both are marked deprecated in favour of the apps family. Version 2.14.0 of the CLI made apps commands and cloud deploy reject malformed resource IDs before calling the API. apps link writes the app and environment IDs into webflow.json for a fresh clone without creating or deploying anything.

Apps deployed with apps deploy are uploaded from local files and are not connected to a repository. That has one practical consequence covered below: apps deployments trigger and redeploy need a GitHub-connected app.

Environment variables and secrets

Rules

  • Each environment supports up to 110 variables.

  • Variables are available at build time and at runtime.

  • A secret is encrypted and masked in the Dashboard (the eye icon reveals it to people who may see it) and redacted from build logs. Redaction is a safety net, not a licence to print secrets: never log them.

  • Variables belong to the current deployment of the environment. A previous deployment does not keep its own copy of the values, so a rollback uses today’s variables with yesterday’s code.

  • Anyone with access to the app can read non-secret variables. Store every sensitive value as a secret, and remember that only values deliberately exposed to the browser, such as a variable whose name starts with NEXT_PUBLIC_ in Next.js, reach site visitors.

  • A change takes effect with the next deployment: after adding, editing or deleting a variable, push a commit or trigger a deployment.

In the Dashboard

Open the environment’s Deployments Dashboard, choose Environment Variables, then Add variable and either Add single variable or Bulk import. Bulk import accepts a .env file; review the parsed variables, mark the sensitive ones as secrets and import. Webflow Cloud warns about key names that look sensitive, such as keys containing the word secret or token.

From the CLI

# non-secret value, set directly
webflow apps env-vars set GARDEN_REGION_LABEL "Fernbrook North" \
  --app-id REPLACE_WITH_APP_ID --environment-id REPLACE_WITH_ENVIRONMENT_ID

# secret, read from standard input so it stays out of history and the process list
printf '%s' "$NURSERY_FEED_KEY" | webflow apps env-vars set NURSERY_FEED_KEY --secret \
  --app-id REPLACE_WITH_APP_ID --environment-id REPLACE_WITH_ENVIRONMENT_ID

# bulk import, every key marked as secret, values never printed in dry-run
webflow apps env-vars import .env.staging --secret --dry-run \
  --app-id REPLACE_WITH_APP_ID --environment-id REPLACE_WITH_ENVIRONMENT_ID

# list keys only; secret values are always masked
webflow apps env-vars list --json \
  --app-id REPLACE_WITH_APP_ID --environment-id REPLACE_WITH_ENVIRONMENT_ID

Details worth knowing: when value is omitted, set reads piped standard input or prompts. Omitting --secret on an existing key keeps its current secrecy rather than turning it off. list shows the fields key and isSecret by default and --q searches keys only, never values. import with --json omits values from its output, and a partial failure exits non-zero with a breakdown of created, updated, skipped and failed keys. delete <key> removes a variable; it has no --yes flag, so preview it with --dry-run.

The MCP server can list variables for an environment but cannot set them, and it returns values only for non-secret entries; setting a value is a CLI or Dashboard action. See MCP Server and AI Agents.

Reading variables in code

In a Next.js app on Webflow Cloud, variables are read from the runtime environment of the Worker, and storage bindings are read through the Cloudflare context as shown in Webflow Cloud: Storage. The wrangler.json file declares the bindings; Webflow Cloud ignores committed resource IDs and provisions each binding per environment, so the same file serves staging and production. A missing required field or an unparseable wrangler.json fails the build, and the build log names the invalid fields.

Logs and observability

Webflow Cloud keeps two kinds of logs per deployment.

  • Build logs record the pipeline above. Open the environment’s Deployment Dashboard and select the deployment ID (the commit SHA). Use them to debug failures, find slow steps and follow progress.

  • Runtime logs record server-side function execution, errors and console output. Open the Deployment Dashboard and select the Runtime Logs tab.

From the terminal both are paginated and filterable:

# build log of one deployment (the deployment ID is required)
webflow apps logs build REPLACE_WITH_DEPLOYMENT_ID --q "error" --limit 50

# runtime log of an environment, from a point in time, as JSON
webflow apps logs runtime REPLACE_WITH_ENVIRONMENT_ID \
  --since 2026-10-28T08:00:00Z --fields timestamp,message --json

Both commands accept --since (ISO date-time), --q (substring of the message), --limit (default 100), --cursor (from the nextCursor of the previous page) and --fields; build logs can also return the phase. logs build does not fall back to the newest deployment, so a script passes the ID it got from deployments list. logs runtime defaults to the app’s only environment and requires the ID when the app has several.

Usage is observed separately from logs. On the Site’s Usage area, Plan usage shows requests, CPU time and memory against the limits of the plan, with trends. A request is an incoming HTTP or API request that runs app code; subrequests made to other services do not count. CPU time measures only the time code is running, not time spent waiting on the network or timers. Bandwidth is counted with the Site’s overall bandwidth. Usage resets at the start of each billing period, so a quick look at the charts after a launch or a campaign is a good habit.

Retention and the durable record

The Dashboard keeps the deployment history of an environment for as long as the environment exists, and deleting the environment removes it. Treat the history as an operational view rather than an archive. The durable record of what ran is the Git history of the tracked branch: every deployment is labelled with its commit, so any past state can be rebuilt from the repository. Keep release notes, tags and branch protection on GitHub, and export anything that must outlive an environment, such as itineraries, from the storage bindings (see Backups and Recovery for the Webflow-side backups).

Rollbacks

A rollback in Webflow Cloud is a new deployment that runs older code. It does not restore the exact state of the earlier deployment: the variables are the current ones, and the data in SQLite, key-value and object storage is whatever the app has written since.

There are two routes.

  1. Through Git. Revert the branch to the target commit on GitHub and push. The push starts a normal deployment. This keeps the repository and the running app in agreement and is the right choice for anything lasting.

  2. Through the CLI. Redeploy an earlier successful deployment, which re-runs it at its original commit without touching the branch:

webflow apps deployments list --limit 10
webflow apps deployments redeploy REPLACE_WITH_DEPLOYMENT_ID \
  --idempotency-key "rollback-planner-2026-10-28" --dry-run

Remove --dry-run to execute. redeploy needs a GitHub-connected app; apps deployed with apps deploy are not eligible. After a CLI rollback the branch still contains the faulty commit, so the next push to it deploys the faulty code again unless it is fixed or reverted. A failed deployment needs no rollback at all: the environment is still serving the last successful one.

CI and idempotency keys

Two shapes of pipeline

The garden’s repository can drive Webflow Cloud in either of two ways.

  • Git-driven. The GitHub App deploys every push to a tracked branch. The CI workflow only tests the code and, if desired, waits for the deployment to finish. This is the simplest option and needs no Webflow credentials in CI for the deployment itself.

  • CLI-driven. The workflow runs webflow apps deploy (or deployments trigger for a GitHub-connected app) with a Workspace API token. Use it when the repository is not on GitHub or when the release must follow other jobs.

Idempotency keys

apps deployments redeploy, apps deployments trigger and apps environments create accept --idempotency-key. The CLI sends it as the Idempotency-Key header, and a retried step is acknowledged against the first enqueue instead of queueing a second build. Pass something unique per logical operation and stable across retries, such as the CI run ID. trigger and redeploy require an app connected to a GitHub repository.

A GitHub Actions workflow

name: Deploy Visit Planner
on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 22
      - run: npm install -g @webflow/webflow-cli@REPLACE_WITH_PINNED_NEXT_VERSION
      - name: Deploy
        env:
          WEBFLOW_API_TOKEN: ${{ secrets.WEBFLOW_API_TOKEN }}
          WEBFLOW_SITE_ID: ${{ secrets.WEBFLOW_SITE_ID }}
        run: >
          webflow apps deploy --no-input --site-id "$WEBFLOW_SITE_ID"
          --mount /planner --environment production --skip-mount-path-check
      - name: Wait for the result
        env:
          WEBFLOW_API_TOKEN: ${{ secrets.WEBFLOW_API_TOKEN }}
          WEBFLOW_SITE_ID: ${{ secrets.WEBFLOW_SITE_ID }}
        run: |
          DEP_ID=$(webflow apps deployments list --limit 1 --json | jq -r '.deployments[0].id')
          webflow apps deployments get "$DEP_ID" --wait --timeout 300

Pin an exact CLI version in CI because the next tag moves. WEBFLOW_API_TOKEN is read from the environment only and never from webflow.json; keep it in the repository secrets. For a GitHub-connected app, replace the deploy step with a trigger that carries the run ID as its key:

webflow apps deployments trigger --idempotency-key "$GITHUB_RUN_ID" --json

Pitfalls

  • A deployment did not start. The GitHub App lost access to the repository, or the push went to a branch no environment tracks.

  • The site was published but the app did not change. The pipelines are independent; deploy the app.

  • The new variable is not visible. Variables apply to the next deployment; trigger one.

  • A rollback still shows new data. Rollbacks change code only; variables and stored data are current.

  • Broken images or API calls after a mount path change. Hard-coded paths. Build every URL from the base path variable and redeploy.

  • trigger or redeploy refuses to run. The app was created with apps deploy and is not connected to GitHub.

  • --no-input hangs in CI. Pass both --mount and --environment.

  • Timeout read as failure. get --wait exits 1 for both; read the reported status.

  • Secrets in history. Pipe the value into env-vars set --secret rather than passing it as an argument.

  • An old Next.js major fails to build. CLI 2.14.0 restored Webflow Cloud builds for out-of-support Next.js majors; upgrade the CLI first, then the framework.

Change history

  • 2026: the apps command family arrives on the next channel and the older cloud commands are marked deprecated.

  • CLI 2.9.0 adds the --region option and --folder-id for imported standalone apps.

  • CLI 2.14.0 adds session-based authentication without .env tokens, single-React library builds, early rejection of malformed resource IDs, and a changed Ctrl-C behaviour during apps deploy.

  • MCP 2.1 adds Webflow Cloud tools for apps, environments, deployments, logs and variable listing, with dry-run previews and idempotency keys.

The dated list of every platform change is in Product Changes and Deprecations.