Build and deploy a web app

A web app is a front-end you build on your project's generated client SDK — a React single-page app served from your platform, talking to your app's own API. This guide takes one from an empty scaffold to a deployed, public URL: scaffold it, author it, validate it, build it, publish it, and find where it's served. Deployment isn't a separate step — publishing a build is what deploys it.

flowchart LR
  A["webapp init"] --> B["author on<br/>the generated SDK"]
  B --> C["webapp check"]
  C --> D["build"]
  D --> E["publish<br/>(= deploy)"]
  E --> F["precise app<br/>→ public URL"]

Every command below is real; the running example is the Chowk marketplace and a web app named storefront.

1. Scaffold the web app

webapp init registers a web app with your project and scaffolds a Vite + React + TypeScript app under clients/web/<name>, pre-wired to the generated SDK:

cisely precise webapp init storefront

That creates clients/web/storefront, registers it as a ProjectWebapp, and prints its location. Install the workspace so the generated SDK packages resolve:

pnpm install

cisely precise webapp list shows every web app registered in the project.

2. Author on the generated SDK

The scaffold depends on your project's generated web-client SDK as workspace packages — typed wire models, TanStack Query hooks (one per query and command), Zod validators, and a component library. You compose screens from those; you never hand-write a fetch("/v1/…") or a schema. A screen is a few hooks and some markup:

import { catalog } from "@<project>/web-client-queries"

export function Catalog() {
  const products = catalog.useListProducts({ pageSize: 50 })
  if (products.isLoading) return <p>Loading…</p>
  return <ul>{products.data?.items.map((p) => <li key={p.id}>{p.name}</li>)}</ul>
}

3. Validate

webapp check builds the generated SDK and typechecks every web app. It is the same gate the build runs, so a web app that checks locally will pass the build:

cisely precise webapp check
# ok — generated packages built and every web app typechecked

4. Build the project

build validates locally, then builds your project on the server. Builds are numbered build-1, build-2, …

cisely precise build
# → buildId … · buildNumber 2 · build-2

5. Publish — which deploys

publish runs server-side codegen and deploys the result. It provisions the app's substrate (database, event bus, secrets) and serves it — the API server and every registered web app, each on its own durable host:

cisely precise publish request <build-id>
# webappNames: 1: storefront
# status: SUCCEEDED

The webappNames line confirms which web apps were included in the deploy. There is no separate deploy command — publishing a build is the deploy.

6. Find your app's URLs

The deployed URLs are derived from your project's durable app key plus the platform's hosting domain. Each web app is served at https://<name>-<suffix>, where <suffix> is an 8-character hash of the app key. Two ways to see them:

From the CLI

cisely precise app shows the API URL and every web app's URL:

cisely precise app --project storefront-marketplace
api        https://<app-key>.<domain>

WEB APP    URL
storefront https://storefront-<suffix>.<domain>

Add -o json for machine-readable output. --project accepts a slug or id; inside a linked project directory it defaults to that project.

From the web console

Open your project in the web console — the Project page lists the deployed application URLs, the API and each web app, ready to click.

What you get

Each web app is served same-origin with your API: its calls to /v1 route to your app's backend on the very same host — so there is no CORS to configure, the session cookie just works, and the app is live against your deployed backend the moment you open its URL. Ship a new version by building and publishing again; the durable host stays the same.