Reference

Kits

What each kit sets up, what the presets scaffold, and how to write a kit of your own.

A kit is the starting point for kitr new <dir> --kit <name>. It sets up platforms, adds packages and copies components. The preset kits also add real pages, controllers and tests for you to edit.

A kit runs once. After that the project is ordinary, and kitr add and kitr remove change it as usual. Every kit but blank is an npm package (@kitr/kit-<name>), so --kit @acme/starter runs a kit from any package.

kitr new my-app                      # blank
kitr new my-app --kit app
kitr new my-admin --kit dashboard
kitr new my-api --kit server
kitr new my-saas --kit saas --platform site=web,api=server --mode ssr --runtime bun

First time? Run npm i -g @kitr/kitr once. Inside a project, the global kitr runs your project's own version.

Every flag is listed under Create a project.

Base kits

Kit Platforms Packages Components
blank none none none
app site: web({ mode: 'spa' }) query, tailwind, theme, testing none
dashboard site: web({ mode: 'spa' }) http, forms, table, state, tailwind, theme, toast, auth, storage, mocks, testing, devtools icon, button, input, label, card, form, data-table, page-header, empty-state, theme-toggle, app-shell
fullstack site: web({ mode: 'ssr' }), api: server() the dashboard kit without mocks, plus seo, actions, api, realtime the dashboard kit's eleven
server api: server() logger, api, db, realtime, testing. No React. none

blank

Only the config files: package.json, tsconfig.json, an empty kitrrc.ts, biome.json, .gitignore, .env.example and AGENTS.md. No app, no React, no dev server.

The usual next step is kitr add web site for a UI or kitr add server api for a backend. Each writes the files and scripts it needs.

app

The smallest app that runs, and the kit to start with: two pages on the route table, Query for data, Tailwind and the theme tokens, one test. Twenty-five files. Add sign-in, forms, a table or an API with kitr add when the app needs them; each package writes its own config and conventions.

dashboard

A single-page app for an API you already have. Data comes through http, pointed at VITE_API_URL. Sign-in uses tokens. Set VITE_MOCKS=true to fake the API while you build. Eleven UI components are copied into app/components/ui. The dashboard guide builds on this kit.

fullstack

The dashboard kit, rendered on the server, with an API server beside it. The UI calls its server through actions in app/actions/, and api routes in server/routes.ts serve other clients. kitr dev runs both. The full-stack guide walks through it.

server

A backend with no React: routes and controllers, a database hook for any ORM, live channels and tests. The API server guide walks through it.

Preset kits

The presets are a base kit plus a small working app. Each one is also in examples/, unmodified.

Kit Platforms Packages What it scaffolds
saas site (ssr), api the fullstack set without actions and realtime, plus shield, mail, analytics, monitoring sign-in, a guarded app shell, a projects page, an API test
site site (ssr), api query, forms, tailwind, theme, i18n, storage, analytics, seo, api, testing, devtools a prerendered site: home, pricing, a blog, a newsletter form, a test
realtime site (ssr), api query, forms, tailwind, theme, toast, storage, seo, api, realtime, testing, devtools a chat room with rooms in the URL, a test
desktop site: web({ mode: 'spa' }), app: desktop() the dashboard kit plus platform the dashboard kit in Electron, with native dialogs
tauri site: web({ mode: 'spa' }), app: tauri() the dashboard kit plus platform the dashboard kit in Tauri, with typed Rust commands
mobile site: web({ mode: 'spa', pwa: true }), phone: mobile() the dashboard kit plus platform the dashboard kit as an installable PWA and a Capacitor app

saas

A signed-in product on its own API. Sign in with [email protected] or [email protected], password password. The demo users live in memory; swap them for your database.

File What it is
app/routes.ts /sign-in, and the guarded _app layout with the overview and projects pages.
app/pages/projects.tsx A data table of projects with a create form.
server/auth.ts The cookie session and the demo users.
server/controllers/auth-controller.ts Sign-in, sign-up, email verification and password reset.
server/controllers/projects-controller.ts The projects API.
app/validators/projects.ts The schema the form, the controller and the test share.
test/api.test.ts Calls the API in a test.

Sessions are HttpOnly cookies, with CSRF protection on the auth routes. A production build needs SESSION_SECRET (32 or more random characters) and a mail transport. See cookie sessions.

site

A prerendered marketing site: home, pricing and a blog, in English and German. config/seo.ts lists the pages to prerender. The newsletter form posts to server/controllers/newsletter-controller.ts, and test/newsletter.test.ts covers it.

For a static marketing or docs site, start from kitr new my-site --kit app --mode static and kitr add seo; the site kit adds SSR and an API server.

realtime

A chat room. app/channels/chat.ts defines the channel, app/pages/chat.tsx is the room, and server/controllers/messages-controller.ts sends new messages to everyone in it. config/realtime.ts picks the transport: WebSocket by default, or Socket.IO or server-sent events.

desktop, tauri and mobile

The dashboard kit in a native shell, with a home page that uses it. The shell's project lives in platforms/<name>/. The web platform stays, so kitr dev site still runs the app in a browser.

Pick desktop (Electron) unless download size matters most. Electron ships its own browser, so every user sees what you tested. Tauri is much smaller but uses the system webview, which can render differently between machines.

Writing a kit

A kit is a package with kind: 'kit':

// src/kitr.ts, published as the "./kitr" export of @acme/kit-starter
import { definePackage } from '@kitr/core/package'

export default definePackage({
  name: 'starter',
  kind: 'kit',
  kit: {
    description: 'Our standard app: SSR, auth, Stripe and the house components.',
    platforms: { site: { type: 'web', options: { mode: 'ssr' } }, api: { type: 'server' } },
    packages: ['http', 'forms', 'tailwind', 'theme', 'auth', { name: '@acme/stripe', answers: { mode: 'hosted' } }],
    components: ['button', 'form', 'app-shell'],
    files(ctx, projectName) {
      ctx.write('app/pages/home.tsx', `export default () => <h1>${projectName}</h1>\n`, { overwrite: true })
      ctx.scripts.add('deploy', 'acme deploy')
    },
  },
})

packages are added in order, with answers for their questions. files runs last, with the same ctx a package's add() gets (the contract).

Publish it with "kind": "kit" in the kitr block of package.json. Then kitr new my-app --kit @acme/kit-starter runs it.