TILLFORGE · DEPLOYMENTS

Preview before production — with a gate where it counts.

GA

A deployment ships a specific commit to a named environment. Wire the environment to a provider and TillForge builds and ships it for you — clone, build on the runner, deploy through the provider’s own CLI; or leave it tracking-only and report state back from your own pipeline. Previews land freely; production environments can require approvals. Every deploy records the exact commit, so a crash later traces straight back to what shipped.

01Environments

Define preview and production

An environment is a named target — preview, staging, production, whatever your flow needs. Mark the ones that matter --production and set --approvals so a deploy to them waits for sign-off. Preview environments stay open, so a branch or a pull request can go live for review with no ceremony.

bash
# Define your environments. A preview env is open; a production env can
# require approvals before anything lands.
tilldev forge env set acme-api --name preview --url https://preview.acme.dev
tilldev forge env set acme-api --name production --production \
  --url https://acme.dev --approvals 1
tilldev forge env ls acme-api
The gate lives on the environment, not the person
Required approvals attach to the environment, so the rule is the same no matter who runs the deploy — the same posture as branch protection, applied to shipping instead of merging.
02First-party

Let TillForge build and ship it

Wire an environment to a provider and TillForge owns the whole deploy. Connect a provider credential once — a static host (Cloudflare Pages, Netlify, Vercel, Firebase, Surge, Azure Static Web Apps), object storage (AWS S3 + CloudFront), edge functions (Supabase), or a container platform (Railway, Fly.io) — and it’s envelope-encrypted under your org key the moment it arrives; the dashboard only ever shows a hint. Then point an environment at that credential and a build recipe, and every deploy runs on your own CI runner: it clones the exact commit, builds it in the hardened container, and ships the output through the provider’s CLI. The credential is injected into the build only at run time — never stored in the job, never printed in the log.

bash
# 1 · Connect a provider credential once (envelope-encrypted at rest).
tilldev forge provider connect --name "prod cloudflare" --provider cloudflare \
  --credential 'api_token=cf_xxx,account_id=abc123'

# 2 · Wire an environment to it + a build recipe, and auto-deploy on push to main.
tilldev forge env set acme-api --name production --production \
  --provider cloudflare --credential <credential-id> \
  --target 'project=acme-web' --build 'npm run build' --output dist \
  --auto-deploy main

# 3 · Deploy — TillForge clones, builds on the runner, and ships via wrangler.
tilldev forge deploy create acme-api --env production --ref main
tilldev forge deploy logs acme-api <id>        # the live build + ship log
tilldev forge deploy promote acme-api <id> --env production
tilldev forge deploy rollback acme-api <id>    # redeploy a known-good commit
ProviderCredentialTarget
Cloudflare Pagesapi_token (Pages:Edit) · account_idproject
Verceltokenproject_id · org_id
Netlifyauth_tokensite_id
Supabase Edge Functionsaccess_tokenproject_ref · function (optional)
AWS (S3 + CloudFront)access_key_id · secret_access_key · session_token (optional)bucket · region · distribution_id (optional)
Firebase Hostingservice_account (JSON)project_id · site (optional)
Surge.shlogin · tokendomain
Azure Static Web Appsdeployment_tokenenvironment (optional)
Railwaytokenservice (optional)
Fly.ioapi_tokenapp
Desktop bundlessigning: none · pfx · azure_trustedframework · platforms
Desktop bundles — build installers, not a URL
Desktop bundles are a different shape of deploy: instead of shipping to a URL, TillForge builds native installers on the runner and publishes them as release assets. electron-builder cross-builds Linux (.AppImage/.deb) and Windows (.exe/.msi) from one Linux runner; Tauri builds Linux. Point the deploy’s ref at a release tag and the installers attach to that release with published sha256 checksums.
Windows code signing — your choice, per target
Signing is optional and set on the credential. Leave it none to ship unsigned installers (Windows shows a SmartScreen warning; the sha256checksums still prove integrity). Choose Azure Trusted Signing(azure_trusted, recommended) and the private key never leaves Azure’s HSM — the runner holds only a short-lived token — which is also the only path that earns a new certificate public SmartScreen trust. Or bring your own Authenticode certificate (pfx) for an enterprise or legacy cert you already hold. Linux binaries are never run-signed. The signing secret is envelope-encrypted in the vault and only ever reaches the runner as claim-time environment — never the recipe or the build log.

A desktop bundle end to end — connect a signing credential, wire the target (framework · platforms), and cut installers on a release tag:

bash
# 1 · Connect a desktop signing credential (envelope-encrypted at rest).
#     Azure Trusted Signing (recommended) — the key never leaves Azure's HSM;
#     the runner only ever holds a short-lived token.
tilldev forge provider connect --name "desktop signing" --provider desktop \
  --credential 'signing=azure_trusted,tenant_id=…,client_id=…,client_secret=…,\
endpoint=https://eus.codesigning.azure.net,account=my-ts-account,certificate_profile=my-profile'
#     …or bring your own Authenticode cert:
#       --credential 'signing=pfx,cert_base64=<base64 of your .pfx>,cert_password=…'
#     …or skip signing entirely (sha256 checksums still prove integrity):
#       --credential 'signing=none'

# 2 · Wire an environment: electron cross-builds Linux + Windows from one runner.
tilldev forge env set acme-app --name desktop --provider desktop \
  --credential <credential-id> --target 'framework=electron,platforms=linux,windows'

# 3 · Deploy against a release tag — the installers attach to that release,
#     each with a published sha256 checksum. Windows binaries are signed per the
#     credential; Linux is never run-signed.
tilldev forge deploy create acme-app --env desktop --ref v1.4.0
tilldev forge deploy logs acme-app <id>        # the live build + sign + publish log
Auto-deploy on push
Set --auto-deploy main and a push to that branch ships production on its own; mark another environment --auto-preview and every other branch push gets its own preview URL. Push access is the gate, so a fork’s pull request never touches your provider secrets. Watch a build with deploy logs, move a known-good commit forward with promote, or back with rollback.
03Tracking

Or track a deploy you ship elsewhere

Leave an environment’s provider unset and it stays a tracking-only record: you deploy a ref — a branch, a tag, or a release — from your own pipeline and report its state back. The natural path is still preview first, then promote the very same commit to production once it’s reviewed. Because a deploy names a commit, a promotion is provably the thing you already saw, not a fresh build that drifted.

bash
# Deploy a ref to an environment. Previews first — a branch or a PR.
tilldev forge deploy create acme-api --env preview --ref feat/checkout \
  --url https://checkout.preview.acme.dev

# Promote to production by deploying the same commit to the gated env.
tilldev forge deploy create acme-api --env production --ref v1.4.0

# Move a deployment through its lifecycle as your pipeline reports back.
tilldev forge deploy status acme-api <id> --state success
tilldev forge deploy ls acme-api --env production
04Lifecycle

Track every deploy

A first-party deploy moves through these states on its own as the build runs; a tracking deploy is moved by your pipeline. Either way the Deploy tab shows the current state of every environment and the full history beneath it.

StateMeaning
queuedAccepted, waiting to start (or for approval).
in_progressRolling out now.
successLive. This is the current deploy for the environment.
failureThe rollout failed; the previous deploy stays live.
errorThe pipeline errored before it could finish.
inactiveSuperseded by a newer deploy, or torn down.

Each deployment can carry a --url (where the deploy is reachable) and a link to its run. A deployment event fires on every state change, so your own dashboards and chat can follow along.

05Correlation

From deploy to the crash it caused

Because a deployment is pinned to a commit, TillForge can line up commit → deploy → incident. When something breaks after a release, the trail runs from the crash back to the deploy that shipped it and the exact change inside it — the same correlation that powers a pull request’s release view.


Next: Releases & builds for what you promote, or Events & webhooks to wire deploys into your own pipeline. Back to the TillForge overview.