Claude
Skills
Sign in
Back

webflow-cli:cloud

Included with Lifetime
$97 forever

Initialize, build, and deploy full-stack Webflow applications to Webflow Cloud hosting. Supports site-attached deploys (linked to an existing Webflow site) and project app deploys (independent project, no existing site required). Use when creating new projects, deploying existing ones, or setting up CI/CD pipelines for Webflow Cloud.

Cloud & DevOps

What this skill does


# Webflow Cloud

Initialize new projects from templates and deploy to Webflow Cloud. Supports two modes: **site-attached** (deploy to an existing Webflow site) and **project app** (deploy as an independent project, no existing site required).

## Instructions

### Step 0: Verify CLI is installed

```bash
webflow --version
```

If the command is not found, install it:

```bash
npm install -g @webflow/webflow-cli@latest
# or yarn global add @webflow/webflow-cli@latest
# or pnpm add -g @webflow/webflow-cli@latest
```

Then proceed to state detection.

### Step 1: Detect project state

Run both checks before deciding which path to follow:

```bash
# Is this project already set up on Webflow Cloud?
cat webflow.json

# Is there a git remote?
git remote get-url origin 2>/dev/null
```

**Quick reference:**

| `cloud.project_id` in `webflow.json` | git remote | → Path |
|---|---|---|
| No | — | **A** — new project |
| Yes | No | **B** — existing project, no git |
| Yes | Yes | **C** — ideal state |

---

> **You are running without a TTY.** The CLI's interactive prompts only fire when `process.stdin.isTTY` is true. As an agent invoking the CLI through a subprocess, you do not have a TTY — every prompt is silently skipped, and any required value that wasn't passed as a flag triggers a hard error like `--project-name cannot be empty`.
>
> **Rule for every command in this skill:** pass all required flags explicitly. Never rely on prompts. Pass `--no-input` when the CLI accepts it to make this contract explicit. The required flag set per command:
>
> | Command | Always pass |
> |---|---|
> | `cloud init` (site-attached) | `--no-input --project-name <3–39 chars> --framework <astro\|nextjs> --mount <path> --site-id <id>` |
> | `cloud init --new` (app) | `--no-input --project-name <3–39 chars> --framework <astro\|nextjs> --workspace-id <id>` |
> | `cloud deploy` (site-attached) | `--no-input --mount <path> --environment <env> --site-id <id>` plus `--project-name` on first deploy |
> | `cloud deploy` (project app, first deploy) | `--no-input --mount <path> --environment <env> --workspace-id <id> --project-name <name>` |
>
> `--site-id`, `--project-id`, `--framework`, and `--workspace-id` on `cloud deploy` let agents override what's in `webflow.json` at deploy time.
>
> **Multi-workspace tokens used to be an agent-fatal hang** because workspace selection had no non-TTY path. Now pass `--workspace-id` to skip the picker. **The workspace ID is not surfaced anywhere in the Webflow dashboard UI** — users can't look it up by hand. If the agent doesn't have it, ask the user to run `webflow cloud deploy` interactively once from inside their project. The preflight prompts for workspace selection and writes `cloud.workspace_id` to `webflow.json`; from that point the agent can read it from the manifest and pass `--workspace-id` on subsequent runs. Do **not** suggest `cloud init --new` for ID discovery — on an existing project it creates a discarded scratch directory. **Exception:** in Path A2 (empty directory) it *is* safe to try `cloud init --new` without `--workspace-id` to auto-resolve a single-workspace token — see [Path A2](#path-a2-empty-directory-scaffold-from-scratch).
>
> **Site IDs are visible in the dashboard.** When `--site-id` is needed but unknown, do not ask the user for a raw `site_XXXX` value — use [`webflow sites list`](#picking-a-site-id-from-a-list) to fetch their sites and present a picker keyed by display name. Users can still check their dashboard to fetch it.

---

### Path A: No `project_id` — new project

The project has not been deployed yet. **Before doing anything else, ask the user one question:**

> "Do you already have source code for this project (an existing Next.js or Astro codebase), or are you starting from an empty directory and want a Webflow starter scaffold?"

That answer chooses the branch — and they're meaningfully different:

| User has... | Branch | Init step |
|---|---|---|
| **Existing code** (their own Next.js / Astro project) | **Path A1** | **Skip `cloud init`.** It would create a `./<project-name>/` subfolder with a hello-world scaffold inside their repo, which they don't want. |
| **Empty directory** or wants a Webflow starter | **Path A2** | Run `cloud init` to scaffold from `Webflow-Examples/hello-world-*`. |

After the branch decision, also ask **site-attached vs app** (only relevant before the first deploy):

| User says... | Mode | Outcome |
|---|---|---|
| "deploy to my Webflow site `<name>`", "site-attached", references an existing site | **Site-attached** | Project is bound to an existing Webflow site; site URL hosts the app at the chosen mount path. Requires `--site-id`. |
| "project app", "standalone", "just an app", "no site", or no existing site mentioned | **Project app** | First deploy provisions a brand-new Webflow site (`<project-name>-<hash>.webflow.io`). |

If the user is ambiguous on either question, **ask**. Do not default.

---

#### Path A1: existing codebase, no Webflow Cloud config yet

The user has working source. `cloud deploy` handles everything — framework detection runs against `package.json`, and the preflight phase resolves identity from flags or prompts the user. No `cloud init` needed, no `webflow.json` to hand-write up front.

**Step 1: One-time auth (human-only).** Tell the user to run this locally; agents cannot drive the browser flow:

```bash
webflow auth login
```

**Step 2: Deploy.** The exact form depends on what the agent knows.

**A1-a — Site-attached, `--site-id` is known:**

```bash
webflow cloud deploy --no-input \
  --site-id site_abc123 \
  --project-name my-app \
  --framework nextjs \
  --mount /app \
  --environment main \
  --skip-mount-path-check \
  --skip-update-check
```

`--framework` is optional if `package.json` has the framework's Cloudflare adapter (`@opennextjs/cloudflare`, `@astrojs/cloudflare`). Pass it explicitly for monorepos or when auto-detection is unreliable.

If the agent doesn't know the user's `--site-id`, do **not** ask for a raw `site_XXXX` value — use [`webflow sites list`](#picking-a-site-id-from-a-list) to fetch the user's sites and present readable display names to pick from.

**A1-b — Project app, `--workspace-id` is known:**

```bash
webflow cloud deploy --no-input \
  --workspace-id ws_abc123 \
  --project-name my-app \
  --framework nextjs \
  --mount / \
  --environment main \
  --skip-mount-path-check \
  --skip-update-check
```

**A1-c — Project app, workspace ID is unknown** (the common gap):

**The workspace ID is not visible anywhere in the Webflow dashboard UI.** Users cannot look it up by hand — the only way to discover it is to run the CLI. So the path is:

**Ask the user to run one interactive deploy locally.** From inside their project directory:

```bash
webflow cloud deploy
```

With no `--no-input` and no identity flags, the preflight prompts: *"This project isn't initialized for Webflow Cloud. How would you like to deploy?"* → user picks "Create a new app" → workspace picker → done. After this one human-driven deploy, `cloud.workspace_id` and `siteId` are written to `webflow.json` and `WEBFLOW_SITE_ID` to `.env`. The agent can then run all subsequent deploys with `--site-id` (the newly provisioned site).

> Do **not** ask the user to run `cloud init --new` to "discover" their workspace ID. On an existing project that creates a discarded `./<project-name>/` scratch directory with a hello-world scaffold inside the user's repo. Use the interactive `cloud deploy` path above — it discovers the workspace ID *and* completes the first deploy in the same step.

**Step 3: Set up git** (if not already) — same as Path A2 step 3 below.

---

#### Path A2: empty directory, scaffold from scratch

1. **Scaffold the project** — pick the form that matches the user's intent:

   ```bash
   # Project app (no site attachment). --workspace-id avoids the multi-workspace hang.
   webflow cloud init --new --no-input \
     --project-name my-app \
     

Related in Cloud & DevOps