Installation

Scaffold a project

Create a new project with the initializer. It's interactive — pick a project type, language, and (for apps and libraries) a styling solution. Use whichever package manager you prefer:

bun create @opentf/web my-app
npm create @opentf/web@latest my-app
pnpm create @opentf/web my-app
yarn create @opentf/web my-app

The scaffolder resolves every @opentf/* dependency to the latest published version on npm, writes the project files, then runs <pm> install with the package manager that invoked it (npm, pnpm, yarn, or bun).

PromptOptions
Project typeSee choosing a project type below
LanguageJavaScript (.jsx) or TypeScript (.tsx + tsconfig.json)
StylingPlain CSS or Tailwind CSS (SPA, Fullstack, and Library only)

Choosing a project type

Not sure which to pick? Each option scaffolds a different shape of project:

OptionWhat it isPick this when…
SPA (browser-only)A normal web app whose UI runs in the browser. You deploy static files (dist/) — no server code in the repo.You want a dashboard, marketing site, or client app with no backend logic (or you call an external API).
Fullstack (browser + server)Same UI plus server files: middleware, API routes, and route loaders. Includes otfw serve for per-request SSR.You need auth, a database, or any logic that must not run in the browser.
Documentation siteAn MDX docs or blog site with navbar, sidebar, and search — powered by @opentf/web-docs.You're building product docs, a handbook, or a content site (like this one).
LibraryA package of reusable components — not a runnable app. Ships with bun test.You're publishing UI primitives or widgets for other apps to install.
SPA vs Fullstack

SPA = browser only, static hosting. Fullstack = browser + server files (middleware, /api/* routes, loaders). If you might add a database or secrets later, start with Fullstack — you can still deploy static output, but the server pieces are already in place.

Start developing

For SPA, Fullstack, and Documentation site projects, start the dev server:

Shell
cd my-app
bun run dev

The dev server compiles each route on first visit. Saving files under app/ rebuilds affected chunks and refreshes the browser tab (full-page reload) — not module-level HMR yet. Restart the dev server after adding a new route folder or changing otfw.config.js.

For Library projects, run the included test suite instead:

Shell
cd my-library
bun test

See Library template for how to publish and consume a component package.

Requirements

OTF Web targets modern browsers and runs its toolchain on Bun or Node 18+.

Production build

Build a static bundle you can host anywhere (App and Docs projects):

Shell
bun run build

See Deployment for build output, hosting, and a fully pre-rendered (Static Generation) site.

Editor setup

The compiler uses a custom JSX pipeline. Point your jsconfig.json (or tsconfig.json) at it so the language server understands your components:

JSONjsconfig.json
{
  "compilerOptions": {
    "jsx": "preserve",
    "jsxImportSource": "@opentf/web"
  }
}

TypeScript projects scaffolded with create-web already include a tsconfig.json and macro typings in app/otfw-env.d.ts.

Why jsxImportSource

It tells your editor where JSX types come from, so autocomplete and type-checking match what the compiler actually emits — without affecting the build.