---
name: deploy-to-surge
description: Publish a static website or built frontend app (Vite, Astro, React, Vue, Svelte, Eleventy, Hugo, plain HTML) to Surge (surge.sh) with the surge CLI. Use when the user asks to deploy, publish, host, preview or share a static project or HTML file on Surge or a *.surge.sh URL, to promote a Surge preview to production, or to roll back a Surge deploy.
license: MIT
compatibility: Needs Node.js 18+ (npx) and network access to surge.sh. Credentials come from the SURGE_TOKEN environment variable.
metadata:
  homepage: https://surge.sh/docs/agents
  version: "1.0"
---

# Deploy to Surge

Surge publishes a directory of static files to `https://<domain>` with one command:
`surge <path> <domain>`. No config file, no dashboard, no server-side build.
Full guide: https://surge.sh/docs/agents (also served as markdown).

Run the CLI as `npx surge@latest`: bare `npx surge` may reuse an old cached version.

## Rules

- Publish a **preview** unless the user explicitly asked for production for this change.
- Use `SURGE_TOKEN` from the environment. Never run `surge login`, never type an
  email or password into the CLI (an unknown email creates a new account), never
  print the token (`echo $SURGE_TOKEN`, `surge token`).
- Only publish to the domain the user named. If none was named, ask, or propose
  `<project-name>.surge.sh` and confirm before publishing.
- Ask before destructive or account-level commands: `teardown`, `discard`, `rem`,
  `nuke`, `dns`, `ssl`, `invite`/`revoke`, `plan`.
- Don't retry a rate-limited publish; retries extend the limit.

## 1. Check the project fits

Surge serves static files only. Fine: any build that writes HTML/CSS/JS to a
directory, or a folder/file of HTML. Not fine: apps that need a server at request
time (Next.js without `output: "export"`, SvelteKit/Nuxt without static output,
Express, Rails, Django, PHP). Tell the user instead of publishing a broken app.

## 2. Build and find the output directory

Run the project's build, then publish the directory it writes:

| Project | Output |
|---|---|
| Vite (React, Vue, Svelte, Solid), Astro | `dist` |
| Create React App, SvelteKit adapter-static, Docusaurus | `build` |
| Next.js `output: "export"` | `out` |
| Nuxt `nuxt generate` | `.output/public` |
| Angular | `dist/<project>/browser` |
| Eleventy, Jekyll | `_site` |
| Hugo | `public` |
| VitePress | `docs/.vitepress/dist` |
| Plain HTML | `.` |
| One HTML file | the file itself (published as `index.html`) |

Confirm the directory has an `index.html`. Client-side routing (React Router,
Vue Router, etc.) needs `cp <out>/index.html <out>/200.html` after every build.
Dotfiles and `node_modules` are never uploaded. Limit: 450 MB, 10,100 files.

## 3. Check credentials

```sh
npx surge@latest whoami
```

Non-zero exit means no valid credentials: stop and ask the user for a token. They
create one with `surge tokens add --domain <domain> -m "agent"` (scoped to that
domain). With a token, `whoami` shows its id and scope.

## 4. Publish a preview

```sh
npx surge@latest <out> <domain> --preview
```

Success ends with:

```
   Success! - Preview available at 1785787164375-my-app.surge.sh
```

- Check the exit code is 0 and that line is present.
- Preview URL = `https://` + that host. Custom domains look like
  `https://1785787164375--example-com.surge.sh`.
- The leading number is the revision id; keep it for step 5.
- Report the URL to the user and stop.

## 5. Production (only when the user approves)

Promote the reviewed revision by id (never a bare `cutover`):

```sh
npx surge@latest <domain> cutover <rev>
```

Or, when asked for a direct production publish: `npx surge@latest <out> <domain>`,
which ends with `Success! - Published to <domain>`.

## 6. Verify and recover

```sh
npx surge@latest <domain> status     # live / securing / waiting on dns / ready
curl -sI https://<domain>
npx surge@latest <domain> rollback   # previous revision, instant; rollfore undoes it
```

`ready` = a new account's domain paused until the user verifies their email
(`surge verify` or the link in their welcome email).

| Output | Do |
|---|---|
| `Aborted - not logged in and no terminal to ask` | Ask for a token. |
| `Invalid token` | Ask for a new token. |
| `you do not have permission to publish to <domain>` | Domain owned by another account or outside the token's scope. Ask. |
| `Rate limited ... Try again in <time>` | Stop; report when it resets. |
| `Project too large` | You're probably publishing the repo, not the build output. |
| Upgrade prompt, `AUTH`/`ROUTER` error | Pro feature: ask the user. |
| `'<x>' is not a surge argument` | Check https://surge.sh/docs/cli/reference |

Custom domains: the DNS records are at https://surge.sh/docs/platform/custom-domains.
Don't change DNS yourself.
