Askr documentation
Guides

Guides

Guides: a worked guide from route registry through to a production build.

Example

Start from an explicit route registry and add one application boundary at a time so browser, server, and production behavior stay testable.

export const registry = createRouteRegistry(() => {
  group({ layout: AppLayout }, () => {
    route('/', DashboardPage);
    route('/projects/{projectId}', ProjectPage);
    route('/404', NotFoundPage);
  });
});

Choose a guide

Each recipe in this section targets a specific shape of application: an SPA, an SSR app, an authenticated full-stack app, an API-only server, a static site, or an MCP server. Pick the one that matches your deployment target rather than reading them in order — `createSPA`, `hydrateSPA`, and `createIslands` are mutually exclusive client execution models, not layers you stack. `createStaticGen` is different: it's a build-time step, commonly paired with `hydrateSPA` (generate HTML, then hydrate it), not a fourth option in the same mutually-exclusive set. If you're not sure which fits, start with the SPA guide and add SSR or static generation later; the router and component code barely changes.

Start from a starter

`askr create startkit my-app` scaffolds a working project with the right `@askrjs/vite` plugin wiring already in place, so you're not hand-assembling `vite.config.ts` from these snippets. `askr create --prompt "..."` picks a template automatically when you describe the app you want. Both write a `.askr/blueprint.json` you can diff against as you follow a guide, which makes it easy to see exactly what a recipe added on top of the base scaffold.

Keep boundaries explicit

Askr's server layer asks you to build dependencies — database handles, auth resolvers, audit loggers — at a single composition root and pass them into route registration functions, not stash them on request context or reach for a service locator. Follow the same pattern on the client: build your route registry with `createRouteRegistry()` once, and pass query and mutation definitions in rather than constructing them ad hoc inside components. It costs a little boilerplate up front and pays off the first time you need to swap a real dependency for a test fake.

Production finish bar

Before calling any of these recipes done, check that `ErrorBoundary` wraps the parts of the tree that can fail at render time, that mutations declared with `defineAction`/`action` invalidate the right query keys, and that routes carrying real auth requirements are marked runtime-only rather than accidentally prerendered by `createStaticGen`. Run `askr openapi --check` if you're exposing a contract, since it fails CI on any byte-level drift from the committed spec. None of this is exotic — it's the same checklist every guide in this section ends on.