# Hosting on darting.app

> Put a static web app and optional worker backend online at your own darting.app address, and follow each deployment from project settings.

The thread preview shows work in progress. **Hosting on darting.app** serves your app publicly after it lands on the repository's default branch. Deploying builds that branch, not unmerged thread work: [ship the change](https://darting.dev/docs/ship-it-and-pull-requests/) first.

## Your slug

In Project settings → **Deployment**, choose the web app to put online. Its address is `https://<slug>.darting.app`; HTTPS is automatic. The deploy form suggests a slug based on the project and checks availability as you type your own. You can deploy a build that is already on the default branch, or, when that branch has no app yet, choose **Deploy once merged** to reserve the address and run the build after the first merge. A repository must exist first.

Each deployable merge to the default branch rebuilds and publishes the app. An open PR is not yet a production deploy. If a build fails, the previous version remains live. You can also redeploy from the Deployment tab.

## What deploys

Every hosted app has a **static frontend**: built files served without a running web server. Vite, Astro, Create React App, and plain HTML are supported; Next.js requires static export. Server-rendered apps and persistent Node backends are not hostable, even if they run in a sandbox. The Deployment tab can show when an app is ineligible.

For an optional backend, put `worker/` beside the frontend in the app directory. It deploys as a Workers-runtime service behind `/api/*` on the **same host**. The frontend remains public: a client-side password screen does not make its files private. A Worker cannot rely on a filesystem or long-lived Node process.

## Worker backends

A Worker can call external services without exposing credentials to the browser and use **Durable Objects** for small persistent state. Cron triggers schedule work, but only one run per app can be in flight; a tick arriving mid-run is skipped, not queued.

Worker configuration can set `compatibility_flags`, including `nodejs_compat` when Node built-ins are needed during bundling. That compatibility mode supplies built-ins and globals, **not** a full Node process. CPU limits can be set in the worker configuration for heavier computation; the default per-invocation CPU allowance is 30 seconds, and the configured upper bound is 300 seconds. A scheduled invocation also has a 600-second wall-clock ceiling. A failing request or cron run can be investigated in **Runtime logs** on the deployed app's card: invocation output, exceptions, and outbound request failures are recorded there. Local success is not evidence that an external service will answer the same way from the deployed edge.

## Production variables

Project settings separates **Dev variables** for thread sandboxes from **Production variables** for the hosted app. One map does not silently fill gaps in the other. Publicly prefixed build variables (`VITE_*`, `NEXT_PUBLIC_*`, `PUBLIC_*`, `REACT_APP_*`) can be baked into the frontend from Production variables. Anything in the resulting files is visible to visitors, so never put a secret in a frontend variable.

A Worker declares the secret names it needs in its worker configuration. Values with those names come from Production variables and are bound into the deployed Worker, rather than being shipped with the frontend. Vaulted keys can also bind directly into hosted Workers. Ordinary Worker configuration variables are deployed as bindings, while local worker development variables do not go to production. Updating a Production variable rebinds it to the live Worker; the deployment card warns about missing production values or bindings that could not be updated. See [secrets & environment](https://darting.dev/docs/secrets-and-environment/) and [the vault & login browser](https://darting.dev/docs/vault-and-login-browser/) before handing an app its production credentials.

## Follow the deployment

The **Deployment** tab has a card for each app. It shows whether the app is online, going online, ready for its first merge, or in error. During a build you can see the current step, progress, and **Build log**; afterwards you can inspect the log, the deployed version's commit, and whether that deployment has fallen behind the default branch. The card links to the live URL and, when known, the merged PR behind it. Once a merged PR's code is detected in production, that thread's ship status gains a **Live** stage. While a merge is deploying, the thread shows the wait in its banners and the sidebar shows a spinner; merging and being live are not the same instant.

## When a Worker isn't enough

Durable Objects are the default for small durable state. For requirements they cannot cover well — **user accounts, realtime updates to browsers, or relational data beyond one object** — Supabase is the sanctioned external backend. A Worker can call it with production credentials kept server-side. A traditional always-running backend or a database server cannot be deployed as the app's Worker; choose another host if that's the architecture you need.

If you ask in chat to put an app online **for the first time**, a dedicated **Ship Doctor** thread handles the deployment: it collects the app and slug choice, requests secret *values* securely, deploys the merged code, and checks the live behavior. Existing deployments can be redeployed and diagnosed in the current thread or through the Deployment tab. Preview, Auth, and Proxy Trust Doctors address different sandbox-preview problems — a blocked frame, a development sign-in wall, or a login that fails only behind the preview proxy — not the first production deploy.
