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.