Skip to content

1. Project setup

This tutorial builds Desksmith — a small storefront with a product catalog, an add-to-cart flow, a cart page, a client-only theme toggle, persistence, live updates, and a checkout flow with an async payment call. Each page adds one capability, and every step maps to real, working patterns from examples/desksmith in the Stator repository — and you can skip to the finished app any time with pnpm create stator my-shop --template desksmith.

By the end you’ll have touched every distinctive part of Stator: machines, server rendering with read(), events, a client island, the store, SSE, and async effects.

A catalog of desk goods grouped into categories, with an “Add to cart” button on each product, a cart page that lets you change quantities, and a theme toggle that lives entirely in the browser. We’ll start with the catalog and grow outward.

Desksmith follows the standard layout — state in machines/, pages in routes/, reusable components in templates/:

desksmith/
├── machines/
│ ├── products.ts # the catalog (app-lifecycle)
│ ├── cart.ts # the cart (session-lifecycle)
│ └── checkout.ts # the checkout flow (session-lifecycle)
├── routes/
│ ├── index.stator # the catalog page
│ ├── cart.stator # the cart page
│ └── checkout.stator # the checkout flow
├── templates/
│ ├── base-layout.stator
│ ├── customer-layout.stator
│ ├── product-list.stator
│ └── theme-toggle.stator
├── lib/
│ └── payments.ts # the (pretend) payment processor
├── static/
└── stator.config.ts # optional — added in step 7 for Redis

This is the end state — what you’ll have built by the last step. Create each file when the step that introduces it tells you to; don’t pre-create them now.

Follow Installation first: install @statorjs/stator and typescript. There’s no entry file to write — the stator CLI is the entry point. Add "type": "module" and the CLI scripts to package.json:

{
"type": "module",
"scripts": {
"dev": "stator dev",
"check": "stator check",
"build": "stator build"
}
}

"type": "module" is required — machines, routes, and stator.config.ts are ES modules.

Stator generates per-component type declarations into .stator/types/ so your editor and tsc can type-check component props. A few settings make that work — rootDirs (so the generated declarations resolve alongside your source), allowImportingTsExtensions (the code imports machines with explicit .ts paths), jsx: preserve (the .stator template body is JSX), and including **/*.stator (so the editor language server applies these options to your components rather than TS defaults):

tsconfig.json
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "Bundler",
"lib": ["ES2022", "DOM"],
"strict": true,
"jsx": "preserve",
"allowImportingTsExtensions": true,
"noEmit": true,
"rootDirs": [".", ".stator/types"]
},
"include": ["**/*.ts", "**/*.stator"],
"exclude": ["node_modules", "static", "dist"]
}

tsc ignores the **/*.stator glob (it only compiles the generated .ts), but the language server uses it to give your .stator files completions and type errors with the same options as the rest of the project.

The .stator/ directory is generated, so add it to .gitignore:

.stator/
dist/

Now install dependencies and run stator check — it generates the .stator type declarations and typechecks the whole stack in one step:

Terminal window
npm install
Terminal window
npm run check

stator dev keeps these declarations current as you work, and stator build runs check first — so you rarely run it by hand.

stator dev boots the dev server, auto-discovering machines/, routes/, and static/. For the tutorial the default in-memory store is fine — we’ll add a stator.config.ts for Redis in step 7. During development, .stator files compile as they’re imported — there’s no separate build step to run while you work, and your app runs from its source tree exactly as it will in production.

Terminal window
npm run dev

Visit http://localhost:3000. You’ll get a 404 until we add a route — that’s next.

A project skeleton with a running dev server. In step 2 we define the two machines that hold Desksmith’s state.