# Preview from your own computer (/docs/build/development)



Your developer can run the app on their own computer and share an HTTPS link to it, so you can click through a change before anyone stages it. The preview uses test data, so nothing it does reaches live members.

* **The link works only while it runs.** When your developer stops the preview, the link goes offline. For a link that stays up, [stage the pushed commit](/docs/build/staging).
* **No computer needed in Console.** [Playground](/docs/build/playground) runs the same kind of preview for you in **Developers → Build**.

`domino dev` is the command behind it: it runs the app on the device against hosted test data and shares it through an HTTPS preview URL.

```mermaid
flowchart LR
    Visitor["Visitor"] --> URL["HTTPS preview URL"]
    URL --> App["Dev server on your device"]
    CLI["domino dev"] -->|"starts"| App
    CLI -->|"synchronizes authored behavior"| Test["Hosted test data"]
    App --> Test
```

## Start a preview [#start-a-preview]

### 1. Install from the lockfile [#1-install-from-the-lockfile]

For a Domino starter, install dependencies from the lockfile.

### 2. Check the remote configuration [#2-check-the-remote-configuration]

```sh
pnpm exec domino doctor --remote --json
```

### 3. Start development [#3-start-development]

```sh
pnpm exec domino dev
```

The CLI:

* connects the app to hosted test data,
* synchronizes authored behavior,
* starts the development server,
* prints an HTTPS preview URL.

Members sign in through the app.

| Option                 | Use it to                                                                               |
| ---------------------- | --------------------------------------------------------------------------------------- |
| `--port <port>`        | Choose the port the app's dev server listens on; the CLI passes it as `DOMINO_APP_PORT` |
| `--cloudflared <path>` | Use a Cloudflare Tunnel connector you installed, instead of the one the CLI downloads   |

* **One preview per checkout.** A checkout keeps the same preview address between runs. Starting a second preview from it fails with "This worktree already has a running preview" until the first stops, or 90 seconds after it stopped responding.
* **Sleep does not stop the app.** If your device sleeps or pauses past those 90 seconds, `domino dev` takes the preview back when it resumes and reconnects it without restarting your dev server. It stops instead if another run started this checkout's preview in the meantime, or if Domino refuses the preview, for example because you lost publish permission.
* **Experimental.** `domino dev`'s result, output, and preview transport may change in a minor release.

In Console's **Developers → Build**, use **Select** to point the agent at an element, **Console** to inspect browser messages and attach them to a prompt, the device menu to check 768px and 390px layouts, and the address bar with **Back** and **Forward** to open and move between pages. The address follows navigation inside the preview. See [preview controls](/docs/build/playground#point-to-a-change-in-the-preview). The development-preview gateway supplies these tools without changing the app repository. Staged apps do not include the bridge.

### 4. Edit resources while it runs [#4-edit-resources-while-it-runs]

The CLI checks source files for changes about once a second, skipping `node_modules`, `dist`, `.git`, `.domino`, `.domino-build`, and `.wrangler` directories. This keeps quest synchronization from consuming the sandbox's file watcher limit. Your app's development server handles app hot reload separately.

* **New files join automatically.** Resource files matching the `discover` patterns in `relay.json` join the next synchronization. Adding a `.quest.ts` or `.quest-type.ts` file under the starter's `quests/` directory does not need another manifest entry.
* **Each update reports itself.** After publishing changed resources, `domino dev` prints `Hosted test quests updated.` An update that fails prints `Quest update failed:` and the error, and keeps the last published version. The next good update after a failure prints `Hosted test quests are up to date.` when it publishes nothing new, for example after you revert the change that broke it. Playground's [Map](/docs/build/playground#see-the-campaign-as-a-map) shows the failure until then.
* **Deleted files are not archived.** Deleting a file stops including it in future bundles; it does not archive the remote quest. Run `domino quests archive <key> --reason "…"`, or archive it in Console. See [Archive a quest](/docs/build/publishing#archive-a-quest).

## Share the HTTPS URL [#share-the-https-url]

Preview addresses use `https://<project-slug>--<workspace-hash>.domino.page`.

| Part               | Details                                                                                                                                                                                                                                                                                                                                                                               |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `<project-slug>`   | Globally unique, derived from the project name: **Phantom Breakpoint 2026** becomes `phantom-breakpoint-2026`. A name whose slug is taken, reserved by Domino, or shorter than 3 characters receives a short suffix. Slugs stay fixed, use lowercase letters, numbers, and hyphens, and are limited to 35 characters. Find yours under **Project settings → General → Project slug**. |
| `<workspace-hash>` | 19 characters. Separates workspaces and makes addresses hard to guess. Restarting the same workspace keeps its address.                                                                                                                                                                                                                                                               |

> [!WARNING] Share the printed URL, not localhost
> Share the URL printed by the CLI, not `localhost` or `127.0.0.1`. Requests to that URL reach the app on your device while development is running. Stopping development takes it offline.

Use the preview for work you are ready to show. The app is reachable through that address; member sign-in still controls member access.

## Check before you stage [#check-before-you-stage]

```sh
pnpm test
pnpm exec domino check
pnpm build
pnpm exec domino deploy --preview --environment test --json
```

`pnpm test` runs your tests, including the quest unit tests in `tests/quests.test.ts` ([Test quests locally](/docs/build/testing)). `check` runs configured app checks, bundles quest definitions, and validates offers, badges and your other data definitions as Relay will, naming the file and field of any that fail. Remote preview validates the effective settings.

> [!IMPORTANT] Try the main action yourself
> Neither check proves that a member can finish the main action. Open the app and try it.

### Act as a test member on the preview [#act-as-a-test-member-on-the-preview]

The preview has the same [test toolbar](/docs/build/staging#try-quests-with-the-test-toolbar) as staging, for whoever opens it with a preview link: act as a test member, move them to the next day, and pass their quests, before anything is staged. Your coding agent uses it to check the app's signed-in screens. Everyone else who opens the preview sees the app as before, without the toolbar.

A preview link works only on the preview it was minted for, and only while that preview runs.

> [!DEV] Preview links
> `POST /management/v1/staging/link` with `preview` set to the URL `domino dev` printed (`domino api POST /staging/link body.json` with `{ "path": "/", "preview": "https://<slug>--<hash>.domino.page" }`) returns a one-minute URL on that preview, as a staging link does. Opening it sets a session for that preview host alone, valid 12 hours, which `domino dev`'s app never receives. The link names the same operators a staging link does, and Domino checks their `publish` permission and key on every toolbar request. A URL that is not a running preview of the project answers 404 `preview-not-found`, and the test environment is required. Without the link's session, the preview's `/__domino/toolbar/` paths answer 403 `operator-required`. In every routing mode, the preview reserves `/__domino/staging-access` for the link and the `/__domino/toolbar/` paths for the toolbar. It answers `/__domino/toolbar.js` with the toolbar's script only for the link's session, and adds that script only to that session's pages. The agent steps are under "Check participant flows on staging" in the Domino skill's campaign testing reference (`references/campaign-testing.md`).

For a persistent preview, [stage the pushed commit](/docs/build/staging).

## Configure an existing app [#configure-an-existing-app]

To develop an app you already have, add an `app` section to its `relay.json` and make its dev script listen on `DOMINO_APP_PORT`. [Configure a hosted app](/docs/build/hosted-app) covers the settings, routing, member sign-in, Worker variables, secrets, storage, and the management key your server code receives.

## When Vite is ready but the preview does not start [#when-vite-is-ready-but-the-preview-does-not-start]

In Console's Playground, select **Upgrade with AI** if the project needs a newer CLI or still uses bundled package archives. The Playground checks for CLI 1.0.0 or newer before starting the preview, while keeping the agent available. Older CLIs build quests the API no longer accepts, which shows as `Unsupported evaluator protocol` when the preview starts. It does not change your dependencies until you select the upgrade action. After the agent finishes, select **Start the preview**.

If Vite reports that it is ready but the CLI says "The app did not start. Check its dev script.", check the CLI version installed in your project. Older CLIs check the app without requesting HTML. Apps with a browser-only page fallback, including the Classic starter, can return 404 to that check even though the page works in a browser. Upgrade the project's `@domino-sdk/relay-cli` and restart the preview. Current readiness checks request HTML from both the local app and its shared preview URL.

If startup still fails, confirm that the dev script listens on `DOMINO_APP_PORT` and that `/` returns a successful response to a request with `Accept: text/html`.

## When Vite blocks the preview host [#when-vite-blocks-the-preview-host]

Current starters configure the preview hostname from `DOMINO_PREVIEW_ORIGIN` through [`dominoHosting()`](/docs/build/hosted-app#run-the-dev-script-on-the-preview-port). An older app may show an allowed-host error. To fix it:

* On the Cloudflare Vite plugin, use `dominoHosting()`'s `server` settings, or add the exact preview hostname to Vite's `server.allowedHosts`.
* Configure HMR for that HTTPS preview.
* Preserve your existing Vite settings. Do not allow every host.

## When Vite reaches the file watcher limit [#when-vite-reaches-the-file-watcher-limit]

If Vite exits with `ENOSPC` and `syscall: 'watch'`, the environment could not allocate another file watcher. Reduce unnecessary watched directories or enable Vite's `server.watch.usePolling`. Polling uses more CPU.

Domino's hosted playground and build sandboxes configure at least 524,288 watches per user at startup. For `domino dev` on your own Linux machine, check `fs.inotify.max_user_watches` on that machine. See [Vite's file watcher troubleshooting](https://vite.dev/guide/troubleshooting#vite-crashes-with-enospc-error).

## Always on test data [#always-on-test-data]

`domino dev` always uses the hosted test environment with real sign-in and providers. The local runtime, `--offline`, and `--review-mode` options have been removed. Keep your project in the `test` environment while developing.

> [!DEV] Output streams
> Development subprocess output goes to stderr so stdout remains available for the CLI result. Use `--json` for a structured result when the development session stops; progress and app logs continue on stderr while it runs.

## Troubleshoot member sign-in [#troubleshoot-member-sign-in]

| Symptom                                                                                                          | What to do                                                                                                        |
| ---------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- |
| A hosted app shows "Participant sign-in is unavailable"                                                          | Domino has not finished configuring sign-in on the shared API. Contact Domino; changing your app will not fix it. |
| Your server route receives 404 "Participant requests must come through a registered app or identity integration" | Check that the app runs as a staged build or a `domino dev` preview.                                              |
| You use an SDK release before 0.10.0                                                                             | Pass `hosted: true` to `proxyParticipant`.                                                                        |

For configuration or build failures, read [Troubleshooting](/docs/reference/troubleshooting).
