Skip to content
flypod
Guides

Deploy a site

Deploy a folder or a single file to a live URL, with auto-detection of common build directories and machine-readable output for scripts.

Point flypod at a directory of static files:

npx flypod ./dist

flypod zips the folder, POSTs it to the server, and prints a live URL:

https://a3f1c2d4e5b60789.flypod.page

Open it. The site is live. You can also deploy a single file:

npx flypod ./index.html

flypod deploy ./dist is the same command, spelled out.

What gets uploaded

Everything in the folder, at any depth, except .git, .hg, .svn, node_modules, .DS_Store, Thumbs.db, .env and .env.*. To leave out more, put gitignore-style patterns in a .flypodignore file in the folder. Whatever was left out is listed after the deploy (skipped in --json).

On flypod.dev a deploy may be at most 200 files and 10 MB. The CLI checks before uploading and fails with too_large, naming the limit, instead of sending a build the server would refuse.

Let flypod find the folder

Run with no path and flypod auto-detects a build directory: the first of these that contains an index.html:

dist/  build/  out/  .output/public  .vercel/output/static  public/  _site/
npx flypod

Auto-detection only matches a directory that actually contains an index.html. If none do, pass the path explicitly.

What the output looks like

In a terminal, flypod prints a short receipt:

  ✓ Deployed in 0.9s · 12 files · 1.2 MB

  https://a3f1c2d4e5b60789.flypod.page

  expires   19 Oct 2026      in 14 days
  keep it   flypod login     free · removes the expiry
  update    flypod update    publishes a new version · same URL

Add --verbose for more rows of the same receipt: the rollback and history commands, and the site id, version id and source folder. Warnings always show, between the URL and the grid.

The split never changes:

  • The live URL goes to stdout, whenever stdout is not your terminal. At a terminal you see it once, in the receipt.
  • Everything else goes to stderr.

So URL=$(npx flypod ./dist) captures just the URL. When stdout is not a TTY (a pipe, a CI job, an agent), flypod auto-detects it and strips the animation. No flag needed.

Machine-readable output

For structured output, use --json and parse stdout:

npx flypod ./dist --json
{
  "ok": true,
  "action": "created",
  "url": "https://a3f1c2d4e5b60789.flypod.page",
  "site_id": "a3f1c2d4e5b60789",
  "version_id": "8f1a0c2e44b7d913",
  "expires_at": 1782929906088,
  "healed": ["spa-fallback"],
  "warnings": [],
  "link_saved": true,
  "next": {
    "update": "flypod update",
    "versions": "flypod versions",
    "rollback": "flypod rollback",
    "keep": "flypod login --json"
  }
}

action is "created" on a folder's first deploy and "updated" when the folder already had a site (see below). expires_at is epoch milliseconds on an anonymous deploy, and null on an owned one. next holds the literal commands for what comes after (keep only appears while the site can still expire). The receipt carries no tokens; --json --verbose adds manage_token and claim_token, along with file and byte counts, timing, and the expiry as expires_in_days and expires_at_iso. The one exception is link_saved: false on an anonymous deploy: then the default receipt includes manage_token, because nothing else is holding it.

For the bare minimum, use --quiet. The URL is the only thing on stdout, and nothing else is printed (unless the folder link could not be saved for an anonymous site; see below):

URL=$(npx flypod ./dist --quiet)

Owned vs anonymous

If you are logged in, the deploy is owned and permanent. If not, it is anonymous and expires after 14 days. Running flypod login later automatically claims every anonymous site this CLI remembers — no tokens to copy. --json --verbose also includes a claim_token for the rare case where you need to claim a site from a different machine. See Accounts & claiming.

After a successful deploy, flypod records a link between the current folder and the site it deployed to. This lets flypod update, flypod versions, and flypod rollback work without an ID. The link lives in a per-user config directory (not in your repo), and recording it is best-effort: if it fails, the deploy still succeeds.

That link also holds the site's manage_token (mode 0600), which is why the deploy output never prints one, and why flypod login can later claim every anonymous site this machine remembers in one step. If the link can't be written — a read-only or ephemeral config dir — flypod says so loudly and prints the token, because nobody else is holding it at that point. flypod token reveals it on demand the rest of the time.

Running flypod again in a linked folder updates that site: same URL, a new version, exactly as flypod update does. If the folder's site is gone (deleted, or expired), flypod makes a new one instead.

To make a separate site from a folder that already has one, run flypod --new. It creates a new site at a new URL and points the folder at it. The CLI says so before uploading, and --json reports the previous site as replaced_link; the old site stays live until it expires.

Flags

FlagEffect
--jsonEmit a JSON object on stdout.
--verboseThe full receipt, in the terminal or with --json.
-q, --quietURL on stdout, nothing else.
--newMake a separate new site, even though this folder already has one.
--commentsTurn on comments for the site (needs a signed-in deploy). See Enable comments.
--mode <mode>With --comments: anonymous (default), passcode or approved.
--timeline / --no-timelineTurn the version History chip on or off for the site. See Update & rollback.
-h, --helpPrint usage.
-v, --versionPrint the flypod version.

Next steps

On this page