Data APIs


Import

import {
action,
liveQuery,
query,
revalidate,
useAction,
useSubmissions,
} from "@solidjs/router";

query

function query<T extends (...args: any[]) => any>(
fn: T,
name: string
): CachedFunction<T>;

Returns a cached function with key helpers:

type CachedFunction<T extends (...args: any[]) => any> = ((
...args: Parameters<T>
) => ReturnType<T>) & {
key: string;
keyFor(...args: Parameters<T>): string;
};
const getUser = query(fetchUser, "users");
getUser.key;
getUser.keyFor("42");

Cache keys combine name with a stable JSON serialization of the arguments. Plain object keys are sorted during serialization.

When fn is a server function without a declared method, query wraps it as a GET server function.

Cache methods

query.get(key: string): any;
query.set<T>(key: string, value: T): void;
query.delete(key: string): boolean;
query.clear(): void;

query.get returns the settled cached value. query.get throws when no entry exists. query.set does not accept a promise value.


liveQuery

function liveQuery<T extends (...args: any) => any>(
fn: T,
name: string
): LiveFunction<T>;

Declares a keyed query over an async-iterable producer. Each value the producer yields is the next value of the query. The producer must yield the current state each time it is invoked.

type LiveFunction<T extends (...args: any) => any> = ((
...args: Parameters<T>
) => AsyncIterable<Value>) & {
key: string;
keyFor(...args: Parameters<T>): string;
status(...args: Parameters<T>): LiveQueryStatus;
};
type LiveQueryStatus =
"idle" | "connecting" | "connected" | "reconnecting" | "closed";

Value is the producer's yielded type, or its resolved return type when it does not return an iterable.

const roomMessages = liveQuery(getMessages, "messages");
const messages = createMemo(() => roomMessages(props.room));
  • Keys combine name with the arguments, as query keys do.
  • Consumers of one key share one connection. A late consumer receives the latest value first. The connection closes when the last consumer leaves.
  • A stream that has delivered a value and then fails with a network error or a 5xx status reconnects with exponential backoff. The latest value stays available meanwhile.
  • A failure before the first value, or a 4xx status, ends the channel and throws to consumers.
  • When fn is a server function without a declared method, liveQuery wraps it as a GET server function.
  • A call under preload intent connects the channel and holds it open for 5 seconds.
  • Mutations do not revalidate live keys. revalidate(key) with force reconnects the matching channels.
  • On the server, the document renders the first value. Hydration adopts it and reconnects.
  • status(...args) is a reactive read of the channel's connection state.

revalidate

function revalidate(key?: string | string[] | void, force?: boolean): void;

Retriggers live matching cache entries. Keys match by prefix. Omit key to match all entries. force defaults to true and marks the matched entries stale before retriggering them.


action

function action<T extends any[], U = void>(
fn: (...args: T) => Promise<U>,
name?: string
): Action<T, U>;
function action<T extends any[], U = void>(
fn: (...args: T) => Promise<U>,
options?: { name?: string }
): Action<T, U>;
type Action<T extends any[], U, V = T> = ((
...variables: T
) => Promise<NarrowResponse<U>>) & {
url: string;
with<A extends any[], B extends any[]>(...args: A): Action<B, U, V>;
onSubmit(hook: (...args: V extends any[] ? V : T) => void): Action<T, U, V>;
onSettled(
hook: (
submission: Submission<V extends any[] ? V : T, NarrowResponse<U>>
) => void
): Action<T, U, V>;
};

Form-compatible actions implement Solid's serializable JSX attribute value. Client actions need a stable name when rendered on the server. Server functions supply their own URL.

Form use

<form action={save} method="post">
<button>Save</button>
</form>

Only POST forms are accepted by delegated action handling. The form has aria-busy="true" from its delegated submission until the action's held update commits. Busy state is keyed by the form's action URL, so every form posting to that URL shows it. The router does not overwrite or remove an aria-busy value the author set.

with

Binds leading action arguments and returns an action for the remaining arguments. The bound arguments are represented in the action URL.

onSubmit

Registers a callback that runs before the mutation call. Registration under an owner is removed when the owner is disposed.

onSettled

Registers a callback for every completed invocation. The callback receives a Submission, including for void, redirect, and metadata-only outcomes. Callbacks run when the action's held update commits, after any revalidation or redirect it holds has rendered. The submission record appears in useSubmissions at the same point.


useAction

function useAction<T extends any[], U, V>(
action: Action<T, U, V>
): (...args: T) => Promise<NarrowResponse<U>>;

Binds direct action invocation to the current router context. The returned promise resolves when the action body finishes, which can be before the action settles and onSettled runs.


useSubmissions

function useSubmissions<T extends any[], U, V>(
action: Action<T, U, V>,
filter?: (input: V) => boolean
): Submission<V, NarrowResponse<U>>[];

Returns a reactive array proxy of settled records for the action. The router retains only records with a result or error.

type Submission<T, U> = {
readonly input: T;
readonly result?: U;
readonly error: any;
readonly url: string;
clear(): void;
retry(): void;
};

Last updated: 10/15/26, 9:29 AMEdit this pageReport an issue with this page