Getting started with a generated lofi app
This guide begins after installing Deno 2.9 or newer.
Create and run the app
deno run -A jsr:@nzip/lofi/create my-app
cd my-app
deno task dev
Open the URL printed by Astro. The starter contains a task list, an account panel when sync is available, and device/runtime diagnostics.
Verify the local-first baseline before changing anything:
The default app is local-only. It does not require an .env, an account ceremony, or a backend.
Run the project checks
deno task doctor
deno task test
deno task build
deno task preview
doctor checks the project layout, configuration, manifest, and referenced install assets without
printing values. test runs the fast, deterministic suite. build creates the production PWA in
dist/, then verifies its base-aware HTML links, manifest, worker, build identity, and precache as
one artifact. preview serves that exact output at http://127.0.0.1:4321/ by default.
Know which files to change
| File or directory | Purpose |
|---|---|
src/schema.ts | Tables and typed fields |
src/permissions.ts | Read and mutation policies |
src/app.ts | App name, database name, stable origins, and repository URL |
src/pages/ | Astro pages and shell composition |
src/islands/ | Preact hooks and interactive UI |
src/styles/ | Application styling |
public/ | Manifest, icon, and other product assets |
tests/ | Application and local-first browser tests |
Application hooks import supported runtime seams from @nzip/lofi, as the generated use-tasks.ts
does. The boundary keeps Jazz networking and storage machinery out of product components while
allowing framework fixes to arrive through a package upgrade.
The final package map is intentionally small:
| Import | Supported use |
|---|---|
@nzip/lofi | App configuration, runtime, session, stores, PWA |
@nzip/lofi/access | Private, direct-share, and fixed-role group helpers |
@nzip/lofi/preact | Package-owned Preact hooks and diagnostic UI |
@nzip/lofi/astro | Package-owned Astro/Vite integration |
@nzip/lofi/recipes/file-handler | Optional validated installed-app file import drafts |
@nzip/lofi/recipes/launch-handler | Optional safe installed-window launch routing |
@nzip/lofi/recipes/protocol-handler | Optional allow-listed custom-protocol item links |
@nzip/lofi/recipes/related-app-discovery | Optional presentation-only companion discovery |
@nzip/lofi/recipes/scope-extension | Optional reciprocal cross-origin app-window scope |
@nzip/lofi/recipes/web-share | Optional inbound/outbound text and link sharing |
@nzip/lofi/recipes/window-controls-overlay | Optional desktop titlebar geometry observation |
@nzip/lofi/testing | Local-first Playwright helpers |
@nzip/lofi/{create,dev,...} | Generator and generated-project command entrypoints |
All of these imports resolve through the single version pinned in deno.json. Upgrade that pin to
receive framework fixes; do not copy package files into src/ or import unpublished internal paths.
Direct vendor access is an unsupported escape hatch: isolate it from ordinary product files and do
not expect lofi compatibility guarantees for it.
Customize the application identity first
Before accumulating local data, update src/app.ts:
nameis the human-facing application name.databaseNamenamespaces durable browser storage.repositoryUrlcontrols the starter footer link.credentialOriginslists hostnames you intend to keep stable if you use device credentials.
Also update public/manifest.webmanifest, public/favicon.svg, the page title, and starter copy.
Changing databaseName later points the browser at a different local database. Choose it early so a
cosmetic rename does not make existing device data appear to disappear.
Replace the task example
The fastest path is to change one layer at a time while keeping the app runnable:
Continue with Data and UI for the table-to-island pattern and Permissions before exposing new data.
Add sync only when you need it
Local-only development is the normal starting point. To add managed Jazz sync and account recovery:
deno task jazz:provision
Then follow Sync and recovery. Provisioning makes sync available; each user still chooses whether their existing local account should begin syncing.