API Reference
Every export an application uses, grouped by what it does, with the guide that explains it. Look a symbol up here when you know the name but not the page.
Import Paths
Every pracht package is ESM-only and publishes its types through exports, so
tsc needs "moduleResolution": "bundler" (or "node16"/"nodenext") — see
TypeScript settings pracht requires.
Almost everything comes from @pracht/core. The package declares a browser
condition, so a client bundle automatically resolves to a client-safe subset of
the same entry point — you do not pick a different specifier for the browser.
That condition carries its own type declarations, so a server-only export such
as handlePrachtRequest is a compile error in client code rather than a
bundling failure. New create-pracht apps enable the condition in their
generated tsconfig.client.json; keep it in custom client TypeScript
configurations:
{
"compilerOptions": {
"moduleResolution": "bundler",
"customConditions": ["browser"]
}
}
Without it, TypeScript resolves the root package to the full server-capable
entry even when Vite will build that module for the browser. The generated base
tsconfig.json deliberately keeps that default for server code and tests; the
typecheck script runs both programs. Explicit @pracht/core/server imports
also keep resolving to the server declarations in either program.
| Specifier |
Use |
@pracht/core |
Application code, client and server alike |
@pracht/core/server |
Server-only entry points, mostly for adapters and generated server entries |
@pracht/core/client |
initClientRouter() and hydration state, for custom client entries |
virtual:pracht/capabilities |
The generated browser capability client. See Capabilities |
Companion packages — @pracht/i18n, @pracht/image, @pracht/content,
@pracht/markdown, @pracht/openapi, @pracht/test — are separate installs
and are listed at the bottom of this page.
Defining the App
| Export |
Description |
defineApp(config) |
The route manifest. See Configuration |
route(path, file, meta?) |
One route. See Routing |
group(meta, routes) |
Shared meta for a subtree of routes |
timeRevalidate(seconds) |
ISG time-based revalidation policy. See Rendering Modes |
webhookRevalidate() |
ISG on-demand revalidation policy |
Constraints
Declarative invariants over the resolved graph, enforced by pracht verify.
See Coding Agents.
| Export |
Description |
requireMiddleware(pattern, name) |
Every matching route must run this middleware |
requireShell(pattern, name) |
Every matching route must use this shell |
requireRenderMode(pattern, mode) |
Every matching route must use this render mode |
forbidRenderMode(pattern, mode) |
No matching route may use this render mode |
requireHead(pattern) |
Every matching route must export head() |
Components
| Export |
Description |
<Link> |
Typed client-side navigation. See Routing |
<Form> |
Progressive form submission to an API route or a capability. See Forms |
<Script> |
Third-party scripts with a loading strategy. See Data Loading |
<Suspense>, lazy() |
Code-split a subtree with a fallback. See Rendering Modes |
<ErrorBoundary> |
Catch render errors in a subtree. See Data Loading |
forwardRef() |
Preact's forwardRef, re-exported so an app needs one Preact import path |
Loader Data
| Export |
Description |
defer(promise) |
Mark slow loader data for concurrent resolution. See Data Loading |
use(value) |
Read a Deferred<T>, promise, or settled value inside <Suspense> |
Deferred<T> |
The typed marker returned by defer() |
Hooks
| Export |
Returns |
Description |
useRouteData(routeId?) |
The loader's data |
The active route's loader result. The optional route id types the result; passing an id other than the active route throws. See Data Loading |
useParams() |
Record<string, string> |
Matched dynamic segments. See Routing |
useLocation() |
{ pathname, search } |
The current URL as the visitor sees it, deploy base included |
useSearchParams() |
ReadonlyURLSearchParams |
The query string, reactively. Mutating it throws — navigate instead |
useNavigate() |
(to, options?) => Promise<void> |
Imperative navigation, by path or route object |
useNavigation() |
{ state, location?, formData? } |
Pending state for the current navigation or <Form> submission: "idle", "loading", or "submitting" |
useBlocker(shouldBlock, options?) |
{ state, location, proceed, reset } |
Stop a navigation before it commits — unsaved-changes guards. See Data Loading |
useRevalidate() |
() => void |
Re-run the active route's loader |
useIsHydrated() |
boolean |
false during SSR and the first client render, true after |
useEventSource(url, options?) |
{ status, data, lastEventId } |
Subscribe to a server-sent event stream. status is "connecting", "open", or "closed". See Server-Sent Events & WebSockets |
useCapability(name) |
{ call, data, error, pending, reset } |
Call state for a user-triggered capability call. From virtual:pracht/capabilities |
Navigation
| Export |
Description |
prefetch(target) |
Warm a route's chunks and route-state JSON. See Prefetching |
createHref(routes) |
Build an href() helper from route definitions. pracht typegen generates one for you |
buildHref(...) |
Resolve a route id and params to a URL path |
redirect(location, options?) |
Throw from a loader or middleware to redirect. See Middleware |
notFound(message?) |
Throw to render the app's 404 page. See Data Loading |
PrachtHttpError |
Throw for a structured error response with a status |
Deploy base
For hand-written URLs only — <Link>, href(), and apiFetch() already apply
the base. See Sub-Path Deploys.
| Export |
Description |
PRACHT_BASE |
The configured base, with leading and trailing slashes. "/" by default |
withBase(path) |
Route path → URL path |
stripBase(pathname) |
URL path → route path, or null when the URL is outside the base |
API Routes
| Export |
Description |
defineApi(config) |
Schema-validated handlers with typed args. See API Validation |
json(value, init?) |
A typed JSON Response |
apiFetch(path, options?) |
Typed client for your own API routes |
ApiFetchError |
Thrown by apiFetch() on a non-2xx response |
formDataToRecord(formData) |
FormData → a plain record, arrays for repeated fields |
searchParamsToRecord(params) |
The same for URLSearchParams |
isApiValidationErrorBody(body) |
Narrow a response body to the standard validation-error shape |
Streaming
See Server-Sent Events & WebSockets.
| Export |
Description |
createEventStream(init?) |
A server-sent events Response with a send/close handle |
serializeEventStreamMessage(message) |
Format one SSE frame by hand |
isUpgradeRequest(request) |
True for a WebSocket upgrade request |
Capabilities and Agents
See Capabilities and Agent Trust.
| Export |
Description |
invokeCapability(name, input, ctx) |
Trusted server-side call, including private capabilities |
createCapabilityTestHost(options?) |
Drive capabilities in tests without booting a server |
setCapabilityAuditHook(hook) |
Receive a structured event for every capability call (single slot) |
addCapabilityAuditListener(name, hook) |
Add a named audit sink alongside others; re-registering the name replaces it. Returns an unsubscribe |
setCapabilityApprovalStore(store) |
Persist approvals for the confirmation flow |
createMemoryApprovalStore(options?) |
An in-memory store, for development and tests |
setCapabilityApprovalPrincipalResolver(fn) |
Decide which principal an approval belongs to |
setCapabilityConfirmationSecret(secret) |
Sign confirmation tokens |
defineCapability(config) |
Define one capability. From @pracht/capabilities |
Environment
See Environment Variables.
| Export |
Description |
publicEnv |
Public variables, safe in the client bundle |
PRACHT_PUBLIC_ENV_PREFIX |
The prefix that marks a variable public |
filterPublicEnv(env) |
Reduce an env object to its public entries |
serverEnv |
Server-only variables. From @pracht/core/env/server |
setServerEnv(env) |
Supply the server env from an adapter that has no process.env |
Fonts
| Export |
Description |
defineFont(options) |
Self-hosted font with preload and font-display handling. See Fonts |
| Export |
Description |
useWebVitals(reporter) |
Lazily report CLS, FCP, INP, LCP, and TTFB from a client component. See Performance |
Sessions
From @pracht/session. WebCrypto only, so the same build runs on every
adapter. See Authentication.
| Export |
Description |
createSessionStorage<Data>({ cookie, store, rolling }) |
The app's session storage. Without store, the data travels AES-256-GCM sealed in the cookie; with one, the cookie carries only a sealed id. rolling: true re-commits on every request, turning maxAge into an idle timeout |
sessionMiddleware(storage, options?) |
Loads the session onto context.session and commits changes after the chain. Does not gate |
requireSession(storage, options?) |
The same, plus a gate: page requests redirect to loginPath, API requests get 401 |
createMemorySessionStore() |
In-memory SessionStore for tests and dev. Not a production store |
hashPassword(password, options?) |
PBKDF2-HMAC-SHA256 hash that records its own parameters |
verifyPassword(password, stored) |
Constant-time check against a stored hash |
withSetCookie(response, header) |
Append a Set-Cookie, reconstructing the response when its headers are immutable |
cookie takes { name, secrets, maxAge?, path?, domain?, sameSite?, secure?, httpOnly? }.
secrets is newest-first: the first seals, all of them open, which is what
makes rotation a deploy rather than a mass logout. A __Host-/__Secure-
name is validated at construction and pins Secure on. secure defaults to
on for every request except plain http from localhost/127.0.0.1/[::1],
so a deployment behind a TLS-terminating proxy does not silently lose it.
Expiry is absolute from the last write, and the middleware commits only when
the session changed — see Authentication for the full
model and for rolling.
SessionStorage method |
Description |
getSession(request) |
The session for a request. A forged, tampered, expired, or unknown cookie yields a fresh empty session — never a throw |
commitSession(session, options?) |
Seal and return the Set-Cookie value. Throws when a cookie session exceeds 4 KB |
commit(session, response, options?) |
The same, appended to a response (existing Set-Cookie headers preserved) |
destroySession(session) / destroy(session, response) |
Delete the store record and expire the cookie |
isDirty(session) |
Whether the session changed this request |
Session member |
Description |
id |
Random 128-bit session id |
data |
Read-only snapshot; reading it never consumes a flash value |
get(key) |
Read a value — and consume it, if it was flashed |
set(key, value) / unset(key) / has(key) |
Durable writes and presence |
flash(key, value) |
Write a value that survives exactly one read |
regenerate() |
New id, same data, old store record dropped. Call it on every privilege change — it is what closes session fixation |
SessionStore method |
Description |
get(id) |
The stored record, or null when unknown or expired |
set(id, data, expiresAt) |
Persist the record. expiresAt is Date.now()-style milliseconds |
delete(id) |
Remove the record; must not throw on an unknown id |
Companion Packages
| Package |
Key exports |
Guide |
@pracht/i18n |
defineI18n, createDictionaries, t, tPlural, interpolate, matchAcceptLanguage, parseAcceptLanguage |
i18n Reference |
@pracht/image |
Image, getImageProps |
Images |
@pracht/content |
defineCollection, llmsTxtArtifacts, rawContentArtifacts, parseFrontmatter |
Content Collections |
@pracht/markdown |
defineMarkdownCollection |
Content Collections |
@pracht/openapi |
defineOpenApi, getOpenApiDescriptor |
OpenAPI |
@pracht/session |
createSessionStorage, sessionMiddleware, requireSession, createMemorySessionStore, hashPassword, verifyPassword |
Authentication |
@pracht/capabilities |
defineCapability |
Capabilities |
@pracht/test |
createLoaderArgs, runMiddleware, createFormRequest, submitForm, readJson, readRedirect |
Testing |
Not Listed Here
@pracht/core also exports build-time and adapter-facing internals —
handlePrachtRequest, prerenderApp, buildAppGraph, handleMcpRequest, the
revalidation helpers, the app-graph serializers. They are public because
adapters and generated entries need them, not because applications do. If you
find yourself reaching for one, the corresponding adapter or
CLI command probably already does the job.