Skip to content
Select themeSelect language

Build and deploy an App

An App is the surface other people touch. Everything else in SupaCloud is something you operate; an App is something you hand out — a link a colleague, a customer or a phone opens to submit work and see what came back. Apps live under Build → Apps.

The Apps tab of the Build hub, listing each App with its framework and deployment state.The Apps tab of the Build hub, listing each App with its framework and deployment state.

This is the part that trips people up, because both live behind the same Framework picker and the picker does not name the distinction.

  • A form App — the App’s file tree contains nothing but manifest.yaml. SupaCloud renders the inputs: you declared in that manifest as a form, collects a submission and starts a run from it. You write no HTML. This is the runtime that is generally available and it works on every instance.
  • A hosted frontend — the App carries real source files, which SupaCloud serves as a website. That means either a react or svelte App, which Vite builds into a dist/, or a plain App to which you added any file beyond the manifest, which is served as-is.

So the framework value is not the whole story: a plain App with only a manifest is a form App, and the same plain App becomes a hosted frontend the moment you add an index.html.

  1. Open Build → Apps and choose New app.

  2. Give it a Name (required, up to 200 characters) and an optional Description.

  3. Pick a Framework:

    • Plain HTML — static HTML, CSS and JavaScript, no build step. Also the framework you leave alone for a form App.
    • React (Vite) and Svelte (Vite) — single-page apps compiled by Vite.

    A framework your plan does not include is shown locked with an upgrade link rather than hidden. On the Free plan only Plain HTML is selectable.

  4. Edit manifest.yaml in the editor below the picker. The starter manifest is pre-filled and the framework you picked is stamped into it. If you declare inputs:, the Form pane beside the editor renders them live so you can see the form take shape before the App exists.

  5. Choose Create app. You land on the App’s detail page, which has five tabs: Overview, Editor, Runs, Execute and Settings.

The Editor tab is a browser IDE over the App’s file tree. manifest.yaml is always open and cannot be closed or deleted — it is the App’s source of truth, and the copy stored on the App record is kept in step with it automatically.

Add files with paths relative to the App root. Each path segment may contain letters, digits, dots, hyphens and underscores; . and .. are rejected, and so is a duplicate path. Binary assets are stored separately from text files and are not opened in the editor.

Save writes the name, description and manifest, then upserts every file you changed and deletes every file you removed. Save does exactly that and nothing more — it does not build and it does not deploy. Those are separate, deliberate actions.

An App can own a Postgres schema. Bind one by naming a postgresql resource in the manifest — by its name or its UUID:

app_db: workspace_app_db

On save, SupaCloud creates a schema named app_ followed by the App’s id with the hyphens removed, and re-runs the row-level-security provisioner so the App’s data is isolated to the App. The Settings tab shows the schema name under Persistence, or tells you the App does not use one. Binding must reference a postgresql resource; the managed workflow database is refused, because its isolation is keyed to a workflow namespace rather than to an App.

Per-App SQL migrations are still how the schema evolves. They are checksummed and append-only: once a migration name has been applied, changing its contents is rejected — register a follow-up under a new name instead. Applying is idempotent, so re-running changes nothing.

A build is always explicit — Save never starts one. Request it from Build & preview on the Editor tab, or from the Builds tab of the App’s peek drawer on the board.

A build is content-addressed by the hash of its source, so requesting the same unchanged tree returns the existing build instead of starting another. The five statuses are queued, claimed, building, succeeded and failed. Under the hood the builder installs dependencies with lifecycle scripts disabled and runs Vite with a relative asset base.

The Builds tab shows the status, the artifact and source hashes, when it started, and — when a build fails — the builder’s error message in full. That message is the diagnostic; there is no separate build-log page.

A plain App needs no build to deploy. A React or Svelte App does: deploying one without a succeeded build is refused.

  1. Choose Deploy from the App header (the Editor tab’s action bar on a phone).

  2. Set the route path — the public address segment, e.g. my-app — and a version label. Version defaults to latest, which binds the App’s most recent succeeded build.

  3. Choose the Access mode. A newly deployed App is private by default:

    • Org members (default) — only signed-in members of the App’s workspace can open it.
    • Public — anyone with the link. An explicit opt-in.
    • Password — anyone with the link and the password. Set one under App password; on a redeploy, leaving it blank keeps the current password.
  4. Deploy. The popover then shows the App’s live URL, the route chip and the deploy history, and offers Undeploy and pause/resume.

By default a hosted App is served on the control-plane host, at /a/<workspace>/<route-path> — inside a Content-Security-Policy sandbox that gives it an opaque origin. That sandbox is the point: an App’s JavaScript must never be able to act as the operator who deployed it, and an opaque origin means the page cannot reach the control-plane session even though it is served from the same host. A form App is always served here.

An instance admin can go further and configure a separate content domain. Each hosted deployment then gets its own opaque subdomain on a different registrable domain from the control plane, which moves the isolation down to the network and cookie layer as well as the CSP. When that is configured, the two routes stop overlapping on purpose: a hosted frontend is served only on its subdomain and returns 404 on the path, while a form App stays on the path and returns 404 on a subdomain. Setting that up is an operator task — see Separate-origin App hosting.

A deployed App sometimes needs to call back into SupaCloud — to start a run of itself, or to invoke one of its declared backend functions. That is what the App API token on the Overview tab is for.

Mint it with Generate App API token (workspace admin only, and only once the App is actually deployed). The plaintext scwa_… value is shown exactly once — the server keeps only its hash — so copy it there and then. Generating a new one immediately invalidates the previous one, and Revoke token removes it altogether.

Apps are metered per plan, and the numbers bite earlier than people expect.

Limit Free Pro Enterprise
Apps 1 5 unlimited
Deployed at once 1 5 unlimited
Storage 50 MB 500 MB unlimited
Build minutes per month 0 60 unlimited
Bandwidth per month 1 GB 25 GB unlimited
React / Svelte frameworks not included included included

A Free workspace therefore gets exactly one plain App and cannot build at all — which is consistent, since the frameworks that need a build are not included either. Re-deploying an App that is already live never counts against the deployed-at-once cap, so re-pointing a route is always allowed. Current storage use is shown in the board footer and on the deploy popover.

Every Apps endpoint additionally sits behind the workspace’s Apps entitlement, so a plan without it sees the surface refuse rather than the numbers apply. None of this is edition-gated: an enterprise-licensed self-hosted instance simply gets the unlimited column.

An App is publishable to the marketplace, and its full source tree travels inside the listing — so it installs on a bare instance with nothing to fetch from elsewhere. An App with nothing but a manifest is refused as a listing; publish one that carries real source.

Most useful products are not one primitive, though. If your App needs a workflow behind it, publish the two together as a bundle so one install brings the whole thing — see Publish a marketplace bundle.