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.
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 |
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 |
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
Source: Webflow CLI: Command reference
--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:
-
Open Webflow Cloud and select the app.
-
Choose Log in to GitHub.
-
Connect one or more repositories to the Webflow Cloud GitHub App.
-
Select a repository.
-
Create or select an environment.
-
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. |
|
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 deployorwebflow apps deployfrom 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
Source: Webflow CLI: Agents and CI/CD
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 |
|---|---|
|
Environment to deploy to; it is created when it does not exist. |
|
Mount path. Always pass it with |
|
Name used on the first deployment. |
|
Subdirectory of the app, for monorepos. |
|
Free-text description of the deployment. |
|
Skips the check of the mount path. |
|
Publishes the Webflow site after the deployment finishes. |
|
Target a site-attached app or a standalone project app. The two are mutually exclusive and fail before any call to the backend. |
|
Override the app from |
Source: Webflow CLI: Command reference
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"
Source: Webflow CLI: Command reference
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
Source: Webflow CLI: Command reference
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
Source: Webflow CLI: Command reference
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.
Source: Webflow Cloud: Usage
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.
-
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.
-
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
Source: Webflow CLI: Command reference
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(ordeployments triggerfor 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
Source: Webflow CLI: Agents and CI/CD
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
Source: Webflow CLI: Agents and CI/CD
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.
-
triggerorredeployrefuses to run. The app was created withapps deployand is not connected to GitHub. -
--no-inputhangs in CI. Pass both--mountand--environment. -
Timeout read as failure.
get --waitexits1for both; read the reported status. -
Secrets in history. Pipe the value into
env-vars set --secretrather 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
appscommand family arrives on thenextchannel and the oldercloudcommands are marked deprecated. -
CLI 2.9.0 adds the
--regionoption and--folder-idfor imported standalone apps. -
CLI 2.14.0 adds session-based authentication without
.envtokens, single-React library builds, early rejection of malformed resource IDs, and a changed Ctrl-C behaviour duringapps 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.
Source: Webflow Developer changelog