Point0by 1gr14
  • Меню
    • GitHub
    • Блог
  • Introduction
    • Overview
    • Getting Started
    • Full Overview
    • Benchmarks
    • Points
  • Points
    • Page
    • Layout
    • Component
    • Provider
    • Mountable
    • Query
    • Infinite Query
    • Mutation
    • Action
    • Root
    • Base
    • Plugin
  • Methods
    • Validation
    • Loader
    • Context
    • Middleware
    • Loading & error
    • .with
    • Mapper
    • Transformer
    • Stage Methods
  • Core
    • Navigation
    • SSR
    • RSC
    • Request
    • Response
    • Error handling
    • Env
    • Head
    • MDX
    • Assets
    • File upload
    • OpenAPI
    • Query client
    • Events
    • Infer
  • Engine
    • Engine Config
    • Engine Runtime
    • CLI
    • Dev
    • Build
    • Compiler
    • Generator
    • Project MCP
    • Docs MCP
    • Importer
    • Public dir
    • Testing
    • Deploy
    • Bun or Vite
  • Extra
    • SsrStore
    • CookieStore
    • Basic Auth
    • CORS
    • Cache-Control
    • Compress
  • Examples
    • Basic
    • Vite
    • Better Auth
    • Capacitor
    • Expo
  • 1gr14
    • Главная
    • Start0
    • Поддержать
    • Обучение
    • Группа
    • Блог
    • Автор
  • Сообщество
    • Discord
    • Telegram
  • Опенсорс
    • Point0
    • Route0
    • Error0
    • Flat
  • Аккаунт
    • Войти
    • Регистрация
Point0by 1gr14
Создаю опенсорс во славу Господа Иисуса Христа ☦️
С любовью ко всем разработчикам на свете ❤️
Условия использованияПолитика конфиденциальностиСергей Дмитриев 2026 😎

Stage Methods

  • Раздел: Methods

On this page

  1. How the strip notes read
  2. Setup methods (before the loader)
  3. .ctx
  4. .loader / .clientLoader
  5. .input / .clientInput / .sharedInput
  6. .params / .search / .body
  7. .headers / .cookies
  8. Render methods (mountables)
  9. .with
  10. .mapper
  11. .wrapper
  12. .loading / .error (and the per-type variants)
  13. .head
  14. .clientOnly
  15. Composition methods
  16. .use
  17. .relatedQuery
  18. Routing & networking
  19. .serverUrl / .clientUrl
  20. .basePath
  21. .middleware
  22. .fetchOptions
  23. .rsc
  24. .transformer
  25. .schemaHelper
  26. .errorClass
  27. Query-option defaults
  28. Events
  29. .on / .serverOn / .clientOn
  30. Navigation: prefetch
  31. .prefetchPageOnNavigate / .prefetchPageOnLinkHover / .prefetchPagePolicy
  32. .onPrefetchPage / .serverOnPrefetchPage / .clientOnPrefetchPage
  33. Navigation: scroll
  34. .scrollRestore / .scrollPosition
  35. API description (actions only)
  36. .response
  37. .openapi
  38. .models
  39. Metadata
  40. .tag / .description
  41. Closing methods
  42. Reference: where each method lives

These are the methods you use to declare a point before it is finalized. A point is a chain: it opens with .lets, runs through a sequence of builder methods, and closes with the method that matches its type (.page(), .query(), .mutation(), …). Everything between the opening and the closing call is a stage-method — the code types call this a StagePoint. After the closing call you hold a ReadyPoint, with a different, smaller surface (.useQuery, .route, .id, …) covered on each point's own page.

This page is the reference for stage-methods (and the closing methods that finalize the chain — .page/.layout/.component/.provider/.query/ .infiniteQuery/.mutation/.action/.root/.base/.plugin). Most have their own page — this one links there and gives the one-line gist. A few small setters live only here and are described in full. Each entry says which point types accept it and what the compiler does with it — which of the four strip categories below it falls in, and how ssr and .clientOnly() change that.

export const ideaPage = root.lets
  .page('/ideas/:id') // .lets — opens the chain
  .use(authorizedPlugin) //         ↑ stage-methods
  .ctx(({ request }) => ({ me: getMe(request) })) //
  .loader(({ params }) => ({ idea: getIdea(params.id) })) //
  .head(({ data: { idea } }) => idea.title) //
  .page(({ data: { idea } }) => <h1>{idea.title}</h1>) // .page — closes the chain

How the strip notes read

Point0 server-renders the first page load (when SSR is enabled) and behaves like an SPA only for client-side navigation after that. So most points exist in two bundles at once — a server build and a browser build — and the compiler decides, per method, what goes where. Stripping removes the call's body and prunes the imports that only that code used, so the dependency never lands in that bundle; the chained call itself stays (so the types still resolve). Every method falls into one of four categories:

  • Server-only — cut from the client bundle: its body and the imports it uses are removed, so it never ships to the browser. Safe for secrets, DB access, request headers (it runs only on the server).
  • Client-only — cut from the server bundle: body and its imports removed, so it never bloats the server build, regardless of SSR (it runs only in the browser).
  • Server-and-client — not cut from either bundle: kept in both (isomorphic), nothing pruned. Config and closers that carry no side-specific code.
  • Server-SSR-and-client — cut from the server bundle when ssr: false (or after an earlier .clientOnly() in the chain): body and imports removed from the server build. Kept in the client build always, and in the server build only when SSR is on. This is the render-side family.

.clientOnly() is the switch: it sets the rest of the chain to behave as if ssr: false, so every server-SSR-and-client method after it (.page/.layout/.with/.head/.loading/.error/…) is cut from the server build and runs in the browser only. A point built under ssr: false behaves the same way from the start.

The short .lets.page('/x') form, the variable-name rule, and why some closing methods take no argument are all on the points page — not repeated here.

Setup methods (before the loader)

These shape the point's data and request. They must come before the single .loader(); once the loader is declared, the setup is locked.

.ctx

Per-request server values, merged and handed to every .loader() and later .ctx() that follows. Server-only — cut from the client bundle. It only runs when the point actually has a loader — otherwise there's no request. On every point type. Full page: ctx.

.loader / .clientLoader

The one callback that produces the point's data. .loader is server-only — cut from the client bundle (it runs on the server); .clientLoader is client-only — cut from the server bundle (it runs in the browser). A mountable (page/layout/component/provider) that declares a loader also becomes a query — it gains .useQuery, .fetchQuery, and the rest. Available on every point type except the structural ones. Full page: loader.

.input / .clientInput / .sharedInput

The validation schema for a point's input. .input is server-only — cut from the client bundle (it validates on the server); .clientInput is client-only — cut from the server bundle (it validates in the browser); .sharedInput is server-and-client — not cut from either bundle (it runs on both). On query, infinite-query, mutation, component, provider (and the chain heads — root, base, plugin). Full page: validation.

.params / .search / .body

Route-shaped input schemas. .params and .search validate the URL params and search string of a routed point; .body is the request body of an action. On a non-action routed point .params/.search are server-and-client — not cut from either bundle, because the client needs them to build hrefs. Inside an action they are server-only — cut from the client bundle (the action runs on the server) — as is .body everywhere. On page, layout, action (.params/.search) and action (.body), plus the chain heads. Full page: validation.

.headers / .cookies

Schemas for request headers and cookies. Server-only — cut from the client bundle. On every point type. Full page: validation.

Render methods (mountables)

These describe how a mountable — page, layout, component, provider — turns its data into UI. All of them are server-SSR-and-client: cut from the server bundle when ssr: false (or after a .clientOnly()) — body and imports removed from the server build. Kept in the client build always, and in the server build only when SSR is on.

.with

The builder's swiss-army knife: inject a query, intercept loading/error, pass props, or wrap the render. On every mountable (and the chain heads). Full page: with.

.mapper

Reshape the loaded queries/props into the data the render receives — the same thing the final .provider(fn) does inline. On every mountable (and the chain heads). Full page: mapper.

.wrapper

Wrap everything the rest of the chain renders in a component, without the prop-threading .with(({ children }) => …) gives you. On every mountable (and the chain heads).

export const IdeaPage = root.lets
  .page('/ideas/:id')
  .wrapper(({ children }) => <Card>{children}</Card>)
  .page(() => <h1>Idea</h1>)

.loading / .error (and the per-type variants)

The components shown while a mountable's data is loading or after it errors. The last one found in the chain wins. .componentLoading / .componentError, .pageLoading / .pageError, .layoutLoading / .layoutError target one mountable kind from a shared parent. On mountables and the chain heads (the per-type variants live on root/base/plugin and, for the page/layout pair, on layout). Full page: loading-error.

.head

Set the document head from the point's data (a string title or an unhead object). The 'global' form, per-status heads, and SEO keys all live on the head page. On page, layout (and root, base, plugin).

.clientOnly

Opt a mountable out of SSR: its render runs in the browser only, and the server bundle drops the render chain. Takes an optional fallback component shown on the server while the client mounts. On page, layout, component, provider (and root, plugin). It is itself server-and-client — not cut from either bundle: the server needs to know to skip the render.

export const ChartPage = root.lets
  .page('/chart')
  .clientOnly(() => <Spinner />) // optional SSR fallback
  .page(() => <HeavyClientChart />)

Composition methods

.use

Inject a plugin — a reusable bundle of stage-methods — into this point's chain, at the position you call it. On every point type. Each method the plugin contributes is stripped exactly as if you'd written it inline.

.relatedQuery

Attach another point's query to this mountable — it goes into the queries array just like a .with(query) result, so its data is available. The difference is prefetch: a related query is statically discoverable, so prefetch self-fetches it without rendering, under the cheap policies (serverQuery / clientQuery / serverAndClientQuery); a .with(query) is only discovered by rendering, so it's prefetched only under the expensive pageDehydratedState* policies (a full SSR render). On mountables and plugins. Server-and-client — not cut from either bundle.

Routing & networking

.serverUrl / .clientUrl

The two origins the app resolves routes against. Root only (and plugin). .serverUrl is where the server and the API live; .clientUrl is the public origin pages live on, for when that differs (split dev ports, a native shell, a CDN front).

export const root = Point0.lets
  .root()
  .serverUrl(sharedEnv.SERVER_URL)
  .clientUrl(sharedEnv.CLIENT_URL) // optional; falls back to serverUrl
  .root()

The origin is chosen by route kind, not runtime side: page/layout routes resolve against clientUrl (falling back to serverUrl); action and endpoint routes always use serverUrl. A side-dependent origin would mismatch SSR-rendered hrefs during hydration. Server-and-client — not cut from either bundle.

.basePath

A type-level route prefix that every point built off this base inherits. Pair it with a gating plugin for a whole section behind one prefix and one check. Root and base (and plugin). Server-and-client — not cut from either bundle.

export const adminBase = root.lets
  .base()
  .basePath('/admin') // every page/query under adminBase inherits /admin
  .base()

.middleware

Mount raw request middleware on the server — third-party handlers (better-auth), OpenAPI's scalar/swagger UIs, anything that wants the bare Request. On every point type, but it only does anything on the server entry. Server-only — cut from the client bundle. Full page: middleware.

.fetchOptions

Customize the fetch Point0 makes for server queries and mutations — an object (merged) or a function (re-evaluated per request, for a fresh token each time). Calls stack: headers merge, later non-header keys override. On every point type. Server-and-client — not cut from either bundle (the browser makes most of these calls).

.fetchOptions({ credentials: 'include' })
.fetchOptions(() => ({ headers: { authorization: `Bearer ${getToken()}` } }))

.rsc

The point's RSC knobs (elements as data), merged per key down the chain. depth — how deep in the loader output React elements are allowed: 0 (the default) allows an element only as the whole output; 1 also allows elements in first-level fields; arrays don't consume a level. holeTimeoutMs — the deadline for the point's streamed holes, defer() subtrees and promises handed to island props alike (default 60 000, false disables). On every point type (and root/base/plugin — set an app default once). Server-and-client — not cut from either bundle (isomorphic config). Full page: RSC.

.rsc({ depth: 1 })
.loader(async () => ({ hero: <Hero />, cta: <HomeCta label="Join" /> }))

.transformer

Serialize query input and loader output across the wire — pass any tRPC-style transformer (e.g. superjson). Root only (and plugin). Server-and-client — not cut from either bundle (both ends must agree on the format). Full page: transformer.

.schemaHelper

Teach the root how to read one validation library's schemas (detect, extract keys, spot file uploads, emit JSON for OpenAPI). Helpers accumulate — call once per library; the first whose isSuitable matches wins. Root only. Server-and-client — not cut from either bundle. Built-ins ship for zod, valibot, arktype, yup, superstruct, typebox (@point0/core/schema/<lib>). Full surface: validation.

import { zodSchemaHelper } from '@point0/core/schema/zod'

export const root = Point0.lets.root().schemaHelper(zodSchemaHelper()).root()

.errorClass

Set the app's error class. Root only. The default is ErrorPoint0; you may replace it with any class of the same-or-wider structure — your own AppError, or one built with Error0 — and it threads through the chain as the point's error type (a query result's .error, the .on('error', …) argument, the error a .with may return). Server-and-client — not cut from either bundle. Full treatment: error handling.

import { AppError } from '@/lib/error' // your own error class

export const root = Point0.lets.root().errorClass(AppError).root()

Query-option defaults

Set default TanStack Query / Mutation options once, high in the chain. Each setter takes one options object and merges it into the matching default (it does not replace). .queryOptions is the broad one; the rest target one query kind. These default the React-Query behavior, so they are server-and-client — not cut from either bundle.

export const root = Point0.lets
  .root()
  .queryOptions({
    retry: false,
    refetchOnWindowFocus: false,
    staleTime: 60_000,
  })
  .root()
MethodDefaults the…Lives on
.queryOptionsevery queryroot, base, plugin
.mutationOptionsevery mutationroot, base, plugin
.infiniteQueryOptionsevery infinite queryroot, base, plugin
.pageQueryOptionsa page self queryroot, base, layout, plugin
.componentQueryOptionsa component self queryroot, base, plugin
.layoutQueryOptionsa layout self queryroot, base, layout, plugin
.providerQueryOptionsa provider self queryroot, base, plugin
.pageDehydratedStateQueryOptionsthe SSR dehydrated-state prefetch queryroot, base, page, layout, plugin

Each takes the TanStack option type with queryKey/queryFn (or mutationKey/mutationFn) stripped — Point0 owns those — plus Point0's per-query SSR switches ssr and suspend (so .queryOptions({ suspend: 'server' }) on a root or layout makes the whole subtree stream — see the ssr and suspend query options). As a defaults setter, .infiniteQueryOptions takes a partial object, so pageParamFromInput is optional here (it's required on the per-point .infiniteQuery({...}) instead). Calling a setter twice keeps earlier plain keys (last call wins per key); the callback keys onSuccess / onError / onSettled (plus onMutate) chain so every registered callback runs. How these layer with a query's own options is on the query page.

Events

.on / .serverOn / .clientOn

Subscribe to the framework's lifecycle events. .on is server-and-client — not cut from either bundle (it runs on both sides); .serverOn is server-only — cut from the client bundle; .clientOn is client-only — cut from the server bundle. Each types the event for its side. On every point type.

export const root = Point0.lets
  .root()
  .on('error', ({ side, name, error, meta }) => {
    // 'error' is sugar for the four error events
    console.error({ side, name, error, ...meta })
  })
  .root()

The event object carries { side, name, data, error, meta }, where meta is a log-friendly projection of data (points become ids, requests become { method, path }). Full event list and per-side typing: events.

Navigation: prefetch

The trigger setters — .prefetchPageOnNavigate / .prefetchPageOnLinkHover and the .prefetchPagePolicy convenience that fans out into both — are client-only: cut from the server bundle, regardless of SSR (they run in the browser as you move between pages). The exceptions are the .onPrefetchPage family — .onPrefetchPage is server-and-client, and .serverOnPrefetchPage / .clientOnPrefetchPage pin the same hook to one side (see below). On root, base, page, layout (with the exceptions noted).

.prefetchPageOnNavigate / .prefetchPageOnLinkHover / .prefetchPagePolicy

Choose how aggressively a page prefetches, by trigger. .prefetchPagePolicy is the convenience that sets both navigate and hover at once.

.prefetchPageOnNavigate('serverAndClientQuery')        // when a navigation starts
.prefetchPageOnLinkHover('serverAndClientQuery', 200)  // on link hover; 2nd arg = delay (ms)
.prefetchPagePolicy('serverAndClientQuery', 200)       // both triggers + hover delay

.prefetchPageOnLinkHover's delay defaults to 30ms. A per-<Link> or per-navigate prefetch overrides the point default; false / 'none' disables it. .prefetchPagePolicy is not on plugins. Policy values and what each fetches: navigation. serverAndClientQuery is the cheap policy; pageDehydratedState runs a full SSR render and is the expensive one (and the pageDehydratedState* policies require SSR or they throw).

.onPrefetchPage / .serverOnPrefetchPage / .clientOnPrefetchPage

Register a callback that runs during prefetch (accumulates across calls). On root, base, page, layout and plugin.

.onPrefetchPage(async ({ location, props }) => { /* warm something up */ })

.onPrefetchPage is server-and-client — kept in both bundles: it runs in the browser on client-side prefetch and on the server once before the first render. .serverOnPrefetchPage (server-only — cut from the client bundle) and .clientOnPrefetchPage (client-only — cut from the server bundle) are the same hook pinned to one side, for warm-up code whose imports should not cross the bundle boundary.

Navigation: scroll

.scrollRestore / .scrollPosition

Scroll-restoration controls live on the navigation page, with their values and defaults.

API description (actions only)

.response

Declare the response schema of an action — what its handler returns over the wire. Action only. Server-only — cut from the client bundle. Full page: response.

.openapi

Attach OpenAPI operation metadata to an action's endpoint. On action (and base, plugin). Server-only — cut from the client bundle: it shapes the generated spec, which the browser never needs. Full page: openapi.

.models

Register named input schemas the OpenAPI generator emits as reusable components. Root and base. Server-only — cut from the client bundle: it feeds spec generation the browser never needs.

Metadata

.tag / .description

Attach metadata to any point. .tag takes one or more strings, de-dupes, and accumulates; tags ride along in the query key so you can invalidate a group by tag. .description appends (joined with \n\n) rather than replacing. On every point type. .tag is server-and-client — not cut from either bundle (it's part of the query key); .description is server-only — cut from the client bundle. On .use, a child's tags union with the parent's and descriptions concatenate.

.tag('ideas', 'public')              // variadic, de-duped, accumulates
.description('Fetch one idea by id') // appends if called again

.tag and .description are point metadata — they do not become an OpenAPI operation's tags or description. The generator reads neither; an operation's tags, description, and the rest of its metadata come only from .openapi({ tags, description }) on an action. Beyond that, the generator sets operationId from the point, and a summary (the point id) for non-action points.

Closing methods

The call that finalizes the chain and turns the StagePoint into a ReadyPoint. Each one matches a point type and has its own page; here is only its strip category.

  • .page / .layout / .component / .provider — the mountable closers. Server-SSR-and-client: cut from the server bundle under .clientOnly() or ssr: false; kept in the client build always. Pages: page, layout, component, provider.
  • .query / .infiniteQuery / .mutation — the data closers. Server-and-client: the closer itself is not cut from either bundle; the loader it wraps is the part that's cut from the client. Pages: query, mutation. Any mountable with a .loader can close with .infiniteQuery({...}) to make its self-query infinite instead of the default finite.
  • .action — the endpoint closer. The action's server handler is server-only — cut from the client bundle; only the route metadata the client needs to call it stays. Page: action.
  • .root / .base / .plugin — the structural closers (no render, no handler). Server-and-client — not cut from either bundle (pure isomorphic config). Pages: root and base, plugin.

Reference: where each method lives

The authoritative per-type availability, straight from the builder types. "all" = every point type (page, layout, component, provider, action, query, infinite-query, mutation, root, base, plugin).

MethodAvailable onStrip category
.ctxallserver-only
.loaderallserver-only
.clientLoaderall but actionclient-only
.inputquery, infinite-query, mutation, component, provider; root, base, pluginserver-only
.clientInputsame as .inputclient-only
.sharedInputsame as .inputserver-and-client
.params / .searchpage, layout, action; root, base, pluginserver-and-client, but server-only under an action
.bodyaction; root, base, pluginserver-only
.headers / .cookiesallserver-only
.with / .mapper / .wrappermountables; root, base, pluginserver-SSR-and-client
.loading / .errormountables; root, base, pluginserver-SSR-and-client
.pageLoading / .pageError / .layoutLoading / .layoutErrorroot, base, plugin, layoutserver-SSR-and-client
.componentLoading / .componentErrorroot, base, pluginserver-SSR-and-client
.headpage, layout; root, base, pluginserver-SSR-and-client
.clientOnlypage, layout, component, provider; root, pluginserver-and-client
.relatedQuerymountables; pluginserver-and-client
.useallper contributed method
.middlewareallserver-only
.fetchOptionsallserver-and-client
.rscallserver-and-client
.transformerroot, pluginserver-and-client
.serverUrl / .clientUrlroot, pluginserver-and-client
.basePathroot, base, pluginserver-and-client
.schemaHelper / .errorClassrootserver-and-client
.queryOptions / .mutationOptions / .infiniteQueryOptionsroot, base, pluginserver-and-client
.componentQueryOptions / .providerQueryOptionsroot, base, pluginserver-and-client
.pageQueryOptions / .layoutQueryOptionsroot, base, layout, pluginserver-and-client
.pageDehydratedStateQueryOptionsroot, base, page, layout, pluginserver-and-client
.onallserver-and-client
.serverOnallserver-only
.clientOnallclient-only
.prefetchPageOnNavigate / .prefetchPageOnLinkHoverroot, base, page, layoutclient-only
.prefetchPagePolicyroot, base, page, layoutclient-only
.onPrefetchPagebase, page, layout, pluginserver-and-client (client + server prefetch)
.serverOnPrefetchPagebase, page, layout, pluginserver-only
.clientOnPrefetchPagebase, page, layout, pluginclient-only
.scrollRestore / .scrollPositionroot, base, page, layout, pluginclient-only — see navigation
.responseactionserver-only
.openapiaction; base, pluginserver-only
.modelsroot, baseserver-only
.tagallserver-and-client
.descriptionallserver-only
.page / .layout / .component / .provider (closers)their own typeserver-SSR-and-client
.query / .infiniteQuery / .mutation (closers)their own typeserver-and-client
.action (closer)actionserver-only handler
.root / .base / .plugin (closers)their own typeserver-and-client
НазадTransformerДалееNavigation

Enjoying Point0?

Give it a star on GitHub, ask questions, and follow what's new

Star Point0

A star on GitHub helps more developers find Point0
Star on GitHub

Start0

Point0 integrated into the Start0 SaaS boilerplate — the best way to use it
Explore Start0

YouTube

Tutorials, walkthroughs, and updates
YouTube

Discord

Questions and chat in English
Join Discord

Telegram

News channel and chat in Russian
ChannelChat

Twitter

Posts and updates
Twitter