Deploy
Create an app and ship it — push over Git, deploy from CI, and what each push triggers.
Create the app
Open the control UI and go to Apps → New app. Enter a name and slug. Creating the app provisions its git remote; deploys follow each push.
Slug rules: 1–48 chars, lowercase letters/digits/hyphens, starting and ending with a letter or digit. Reserved: _control, app, api, git.
Push with git
Every app has a Git remote at https://git.<domain>/<slug>. Authenticate as user git with an account API key (Account → API keys) as the password; the push needs the push role on the app. Each push to main deploys.
The smallest app is a Wrangler config plus a module Worker:
{
"name": "hello",
"main": "index.js",
"compatibility_date": "2026-09-01",
}
export default {
fetch: () => new Response("Hello from Noite"),
};
git init -b main
git add -A && git commit -m "first deploy"
git remote add origin "https://git:<api-key>@git.<domain>/<slug>"
git push -u origin main
Open the result at https://<slug>.<domain>. With a package.json, the runner installs and builds it first with the project’s package manager (npm, pnpm, Yarn or Bun), so Vite and Rsbuild apps need no CI (Build); without one it deploys the tree as is. The Wrangler config is optional: a static site (a build that writes dist/index.html) or a package.json main that exports fetch deploys without one (No config at all). Pushes must fast-forward unless you hold the admin role.
Your first app, in order
- Create the app and an API key (above).
- Describe the Worker with a
wrangler.jsoncor, if you use thecfCLI, acloudflare.config.ts(which one). Or neither, for a static site or afetchmodule (no config at all). - Add a build if you have one: a
buildscript orbuild.command(Build). - Set env vars in the app’s Settings if the build or release command needs them. They do not reach the running Worker; use
varsin the config for that (Configure). - Push to
main, watch the Deployments tab, openhttps://<slug>.<domain>. - Check what does not run: Node HTTP servers (Express, Fastify,
app.listen()) are refused at deploy (Frameworks and Node servers). Quotas, rate limits and memory bounds are on Limits.
Release command
A release string in the Wrangler config runs once per deploy, after the build and before celld deploy: the place for database migrations.
{
"name": "my-app",
"main": "src/index.ts",
"compatibility_date": "2026-09-01",
"release": "bun run db:migrate",
}
It runs with sh -c in the project with your app’s env vars, and is killed after 10 minutes. The command is capped at 500 characters. A non-zero exit fails the deploy and the previous deployment keeps serving. release is removed from the config before celld deploy.
Deploy from CI
@noitenow/cli pushes a prebuilt dist/ plus wrangler.jsonc as a synthetic fast-forward commit — no server build, push role suffices, never force-pushes.
bunx @noitenow/cli deploy --slug <slug> --url https://git.<domain> --token "$NOITE_API_KEY"
- run: bun run build
- run: bunx @noitenow/cli deploy --comment update
env:
NOITE_API_KEY: ${{ secrets.NOITE_API_KEY }}
NOITE_BASE: https://git.<domain>
| Flag | Env | Default |
|---|---|---|
--dist |
— | dist |
--slug |
NOITE_SLUG |
repo name, slugified |
--url |
GIT_PUBLIC_BASE / NOITE_BASE |
http://git.localhost:9080 |
--token |
NOITE_API_KEY / NOITE_GIT_TOKEN |
— |
--wrangler |
— | wrangler.jsonc |
--message |
— | deploy <sha12> |
--comment |
— | update (create / off) |
In Actions it writes url= + sha= to $GITHUB_OUTPUT and posts (or updates, via marker) a PR comment. A Worker may be declared in cloudflare.config.ts instead of wrangler.json(c) — the runner converts it after the build when no Wrangler config exists.
What happens on push
- Tip
.bundlelands; the runner updates its bare mirror and worktree. - The sandboxed install and build (
build.commandor thebuildscript) run when the tree declares them, with the project’s package manager. - The runner picks the config to deploy: the build’s output when it produced one, else the source config, else one it generates (Which config deploys).
- Optional
releasecommand (e.g. migrations) runs. A failed release keeps the old deployment serving. - The config is stripped of runner-only keys (
release,build), thencelld deployships the fleet; a new fleet spawns or the existing one getsPOST /reload.
The Deployments tab shows status per push with a build-log pane: one ▸ step: command line per step and its output tail, and on failure the step that failed. Deploy logs keep a 64 KB tail.
Rollback
POST /v1/apps/<id>/rollback {sha} redeploys a past successful SHA — bundles are immutable per SHA. The UI offers rollback on success rows.