Cloud|

Install an application as a PWA

Give one application its own installation, neutral start path, generated icons, and offline fallback.

4 min read Updated 2026-10-23 #pwa#installation#offline#routing

Declare installable when people need to open one application from their Home Screen in a standalone window. Each application can declare one installation; several applications can be installed from the same Cloud origin.

This is separate from the Cloud mobile app's pwa parts. The declaration adds no account session, device pairing, or customer-session permissions. Authorize application pages and APIs through the normal server contracts. For a shared customer device, add device pairing and visit sessions.

Declare the installation

ts
import { defineApp } from "@k2b/cloud";

export const app = defineApp({
  id: "inventory",
  name: "Inventory",
  icon: "ti ti-packages",
  description: "Track stock and warehouse movements.",
  baseUrl: "http://app-inventory:3000",
  basePath: "/app/inventory",
  routes: ["/app/inventory", "/api/inventory", "/public/inventory"],
  installable: {
    path: "/app/inventory/counter/",
    name: "Inventory counter",
    shortName: "Counter",
    icon: "ti ti-pencil",
    themeColor: { light: "#fafafa", dark: "#090d12" },
    display: "standalone",
  },
});

name and shortName must be nonempty. icon names an existing outline Tabler icon in the form ti ti-pencil; an unknown icon fails the build. Both theme colors are six-digit hex values. display is "standalone".

path is the installation identity, start URL, and scope. Keep it stable: changing it creates a different installation. It must end in /, start with /app/<this-app-id>/, and contain at least one surface segment after the app id. Surface segments use lowercase letters, digits, and hyphens. Encoding, backslashes, dot segments, queries, fragments, duplicate slashes, and framework paths such as help, _ssr, and _internal are rejected.

A declared route at or below /app/<id> must cover the start path. / or /app alone does not count, and Cloud does not invent route coverage. Mount the matching Hono page routes as described in Routes and discovery. Invalid declarations fail at defineApp() and are rejected by registry readers.

Render the neutral start page

Serve a neutral page at installable.path: show the application name and the next available action without restoring private customer content from browser storage. Use app.ssr() for this page and other pages inside its scope. A standalone application can compose MinimalLayout without the Cloud navigation shell.

Cloud recognizes the actual request path and automatically adds the manifest, Apple Home Screen icon and title, theme color, safe-area padding, service-worker registration, and installation hint. No layout hook or per-page opt-in is required. The same integration applies to app.ssr.error() documents inside the scope. Pages outside it retain their normal document head.

Use the standard build and development scripts. They generate light and dark PNG icons at 192 and 512 pixels, an opaque 512-pixel maskable icon with its artwork inside the safe circle, and a 180-pixel Apple icon. Theme changes update the manifest link, Apple icon, and browser theme color without changing the installation identity.

Install and open the app

Use HTTPS, or localhost for development. In Chromium, Cloud shows Install app when the browser supplies an installation prompt. The browser decides whether installation is available; opening the prompt does not confirm an installation.

On iOS and iPadOS, the hint explains how to open Safari's Share menu, choose Add to Home Screen, and confirm Add. It also recognizes iPads that request desktop websites. The hint follows the request locale in English or German and disappears in standalone mode. If worker registration fails, the page offers Try again and remains usable online.

Installation does not create a separate security origin. Scripts on the same origin share a trust boundary. For a shared customer-facing device, use a separate browser profile without an employee sign-in.

Predict offline and update behavior

The generated worker uses the network for scoped GET navigations. When the network fails, it returns one neutral bilingual offline document with Try again / Erneut versuchen. Retrying reloads the current address. It never stores application pages, API responses, documents, secrets, or signatures. The offline document is embedded in the worker; no Cache Storage is created. API requests, other subresources, POST requests, and other applications pass through to the network.

A worker update waits while a window controlled by the old worker remains open. Close all windows of that installation, then reopen it to activate the update. Cloud sends no activation message, claims no existing windows, and forces no reload. Other installed applications can stay open.

Framework-owned public paths

Cloud serves these paths before application access and authentication middleware. They contain only public installation metadata or generated assets:

Path relative to installable.path Response
manifest.webmanifest Manifest; ?theme=light or ?theme=dark selects presentation, with light as the default
sw.js Worker limited to the declared scope
offline.html The same neutral bilingual fallback document
icon-192-<theme>.png, icon-512-<theme>.png Launcher icons
icon-maskable-512-<theme>.png Opaque maskable icon
apple-touch-icon-<theme>.png Apple Home Screen icon

Here <theme> is light or dark. The routes support GET and HEAD; unsupported methods return 405. A missing generated icon returns 404 rather than reaching application code. Opening the bare start path without its final slash redirects to the canonical path.

Do not serve your own worker in this namespace. The gateway permits only the exact generated sw.js as a worker script and strips scope-broadening headers. It rejects foreign claims anywhere below /app/<id> and prevents a root or ancestor route from answering for another app, including when the owner has no valid registry entry. See the runtime deployment note.

Connect a coding agent

The Cloud skill provides compact working instructions. MCP supplies exact current documentation when details matter.

CLI command
bunx skills add https://docs.example.com

This command installs the working instructions published by this website in the selected coding agent.

For exact, current details, also connect the MCP server through one of the agent tabs.

Installation uses the open-source Vercel Skills CLI.

The skill and MCP complement each other: the skill describes workflows, while MCP supplies current documentation.