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 runs bun install and bun run build first; without one it deploys the tree as is. Pushes must fast-forward unless you hold the admin role.
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. - Sandboxed
bun install/bun run buildrun when the tree declares them. - Optional
releasecommand (e.g. migrations) runs. A failed release keeps the old deployment serving. - The config is stripped of Noite-only keys, then
celld 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. 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.