Learn
Query Data In The Browser
Use the generated client for mutations and the browser query stack for typed reads.
Kizaki gives browser apps two complementary tools:
@kizaki/clientfor calling exposed server functions@kizaki/sdk/browserand@kizaki/reactfor browser-side query objects and live reads
The easiest way to stay sane is to assign each tool a clear job.
Use The Generated Client For Workflows
import { createProject } from "@kizaki/client";
await createProject("Docs rewrite");This is the recommended path for mutations and business workflows.
If an action changes the system, performs validation, coordinates multiple writes, or should stay behind a single typed entrypoint, it usually belongs behind an exposed function and the generated client.
Use Query Objects For Browser Reads
import { select } from "@kizaki/sdk/browser";
import { useQuery } from "@kizaki/react";
import { Project } from "@kizaki/schema";
const projectsQuery = select(Project)
.fields(Project.id, Project.name)
.orderBy("createdAt", "desc");
export function ProjectsList() {
const projects = useQuery(projectsQuery);
if (projects.status === "loading") return <p>Loading...</p>;
if (projects.status === "error") return <p>{projects.error?.message}</p>;
return (
<ul>
{projects.data.map((project) => (
<li key={project.id}>{project.name}</li>
))}
</ul>
);
}Recommended Split
- use generated client calls for actions
- use query objects for data shown in the UI
- let invalidation and live updates keep the browser state current
This gives you a clean architecture:
- browser code stays simple
- server workflows stay centralized
- reads can stay reactive without inventing a second API surface
If you already know a screen should stay live, build the browser read with a query object from the start. You can fetch it once today and keep it live later without rewriting the UI data model.
Continue with Add Realtime.