React Installation and Setup
Add Jazz to your React application in minutes. This setup covers standard React apps, Next.js, and gives an overview of experimental SSR approaches.
Integrating Jazz with React is straightforward. You'll define data schemas that describe your application's structure, then wrap your app with a provider that handles sync and storage. The whole process takes just three steps:
Looking for complete examples? Check out our example applications for chat apps, collaborative editors, and more.
Install dependencies
First, install the required packages:
pnpm install jazz-tools
Write your schema
Define your data schema using CoValues from jazz-tools
.
// schema.ts import {
import co
co,import z
z } from "jazz-tools"; export constTodoItem =
const TodoItem: CoMapSchema<{ title: z.z.ZodString; completed: z.z.ZodBoolean; }>
import co
co.map({
map<{ title: z.z.ZodString; completed: z.z.ZodBoolean; }>(shape: { title: z.z.ZodString; completed: z.z.ZodBoolean; }): CoMapSchema<{ title: z.z.ZodString; completed: z.z.ZodBoolean; }> export map
title: z.z.ZodString
title:import z
z.string(),
function string(params?: string | z.z.core.$ZodStringParams): z.z.ZodString export string
completed: z.z.ZodBoolean
completed:import z
z.boolean(), }); export const
function boolean(params?: string | z.z.core.$ZodBooleanParams): z.z.ZodBoolean export boolean
AccountRoot =
const AccountRoot: CoMapSchema<{ todos: CoListSchema<CoMapSchema<{ title: z.z.ZodString; completed: z.z.ZodBoolean; }>>; }>
import co
co.map({
map<{ todos: CoListSchema<CoMapSchema<{ title: z.z.ZodString; completed: z.z.ZodBoolean; }>>; }>(shape: { todos: CoListSchema<CoMapSchema<{ title: z.z.ZodString; completed: z.z.ZodBoolean; }>>; }): CoMapSchema<...> export map
todos:
todos: CoListSchema<CoMapSchema<{ title: z.z.ZodString; completed: z.z.ZodBoolean; }>>
import co
co.list(
list<CoMapSchema<{ title: z.z.ZodString; completed: z.z.ZodBoolean; }>>(element: CoMapSchema<{ title: z.z.ZodString; completed: z.z.ZodBoolean; }>): CoListSchema<...> export list
TodoItem), }); export const
const TodoItem: CoMapSchema<{ title: z.z.ZodString; completed: z.z.ZodBoolean; }>
MyAppAccount =
const MyAppAccount: AccountSchema<{ root: CoMapSchema<{ todos: CoListSchema<CoMapSchema<{ title: z.z.ZodString; completed: z.z.ZodBoolean; }>>; }>; profile: CoMapSchema<{ name: z.z.ZodString; }>; }>
import co
co.account({
account<{ root: CoMapSchema<{ todos: CoListSchema<CoMapSchema<{ title: z.z.ZodString; completed: z.z.ZodBoolean; }>>; }>; profile: CoMapSchema<{ name: z.z.ZodString; }>; }>(shape?: { root: CoMapSchema<{ todos: CoListSchema<CoMapSchema<{ title: z.z.ZodString; completed: z.z.ZodBoolean; }>>; }>; profile: CoMapSchema<{ name: z.z.ZodString; }>; } | undefined): AccountSchema<...> export account
root:
root: CoMapSchema<{ todos: CoListSchema<CoMapSchema<{ title: z.z.ZodString; completed: z.z.ZodBoolean; }>>; }>
AccountRoot,
const AccountRoot: CoMapSchema<{ todos: CoListSchema<CoMapSchema<{ title: z.z.ZodString; completed: z.z.ZodBoolean; }>>; }>
profile:
profile: CoMapSchema<{ name: z.z.ZodString; }>
import co
co.map({
map<{ name: z.z.ZodString; }>(shape: { name: z.z.ZodString; }): CoMapSchema<{ name: z.z.ZodString; }> export map
name: z.z.ZodString
name:import z
z.string() }), });
function string(params?: string | z.z.core.$ZodStringParams): z.z.ZodString export string
See CoValues for more information on how to define your schema.
Standard React Setup
Wrap your application with <JazzReactProvider />
to connect to the Jazz network and define your data schema:
// app.tsx import {
function JazzReactProvider<S extends (AccountClass<Account> & CoValueFromRaw<Account>) | AnyAccountSchema>({ children, guestMode, sync, storage, AccountSchema, defaultProfileName, onLogOut, logOutReplacement, onAnonymousAccountDiscarded, enableSSR, }: JazzProviderProps<S>): JSX.Element
JazzReactProvider } from "jazz-tools/react"; import {MyAppAccount } from "./schema";
const MyAppAccount: AccountSchema<{ root: CoMapSchema<{ todos: CoListSchema<CoMapSchema<{ title: ZodString; completed: ZodBoolean; }>>; }>; profile: CoMapSchema<...>; }>
function createRoot(container: Container, options?: RootOptions): Root
createRoot lets you create a root to display React components inside a browser DOM node.createRoot(var document: Document
[MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/document)document.Document.getElementById(elementId: string): HTMLElement | null
Returns a reference to the first object with the specified value of the ID attribute.getElementById("root")!).Root.render(children: React.ReactNode): void
render( <function JazzReactProvider<S extends (AccountClass<Account> & CoValueFromRaw<Account>) | AnyAccountSchema>({ children, guestMode, sync, storage, AccountSchema, defaultProfileName, onLogOut, logOutReplacement, onAnonymousAccountDiscarded, enableSSR, }: JazzProviderProps<S>): JSX.Element
JazzReactProvidersync: SyncConfig
sync={{peer: "wss://cloud.jazz.tools/?key=you@example.com"
peer: "wss://cloud.jazz.tools/?key=you@example.com" }}AccountSchema={
AccountSchema?: AccountSchema<{ root: CoMapSchema<{ todos: CoListSchema<CoMapSchema<{ title: ZodString; completed: ZodBoolean; }>>; }>; profile: CoMapSchema<...>; }> | undefined
MyAppAccount} > <
const MyAppAccount: AccountSchema<{ root: CoMapSchema<{ todos: CoListSchema<CoMapSchema<{ title: ZodString; completed: ZodBoolean; }>>; }>; profile: CoMapSchema<...>; }>
function App(): React.JSX.Element
App /> </function JazzReactProvider<S extends (AccountClass<Account> & CoValueFromRaw<Account>) | AnyAccountSchema>({ children, guestMode, sync, storage, AccountSchema, defaultProfileName, onLogOut, logOutReplacement, onAnonymousAccountDiscarded, enableSSR, }: JazzProviderProps<S>): JSX.Element
JazzReactProvider> );
This setup handles:
- Connection to the Jazz sync server
- Schema registration for type-safe data handling
- Local storage configuration
With this in place, you're ready to start using Jazz hooks in your components. Learn how to access and update your data.
Next.js Integration
Normally Jazz doesn't render the children until the account is loaded.
On the server there is no account, but we can ask Jazz to render the children using an "empty agent". An agent is a read-only account that can be used without credentials to render the data available to the public.
import {
function JazzReactProvider<S extends (AccountClass<Account> & CoValueFromRaw<Account>) | AnyAccountSchema>({ children, guestMode, sync, storage, AccountSchema, defaultProfileName, onLogOut, logOutReplacement, onAnonymousAccountDiscarded, enableSSR, }: JazzProviderProps<S>): JSX.Element
JazzReactProvider } from "jazz-tools/react"; import {MyAppAccount } from "./schema"; export function
const MyAppAccount: AccountSchema<{ root: CoMapSchema<{ todos: CoListSchema<CoMapSchema<{ title: ZodString; completed: ZodBoolean; }>>; }>; profile: CoMapSchema<...>; }>
JazzWrapper({
function JazzWrapper({ children }: { children: React.ReactNode; }): React.JSX.Element
children: React.ReactNode
children }: {children: React.ReactNode
children: React.type React.ReactNode = string | number | bigint | boolean | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode> | React.ReactPortal | Promise<...> | null | undefined
Represents all of the things React can render. Where {@link ReactElement } only represents JSX, `ReactNode` represents everything that can be rendered.ReactNode }) { return ( <function JazzReactProvider<S extends (AccountClass<Account> & CoValueFromRaw<Account>) | AnyAccountSchema>({ children, guestMode, sync, storage, AccountSchema, defaultProfileName, onLogOut, logOutReplacement, onAnonymousAccountDiscarded, enableSSR, }: JazzProviderProps<S>): JSX.Element
JazzReactProviderenableSSR?: boolean | undefined
enableSSR // Renders the components tree in the server using an agentsync: SyncConfig
sync={{peer: "wss://cloud.jazz.tools/?key=you@example.com"
peer: "wss://cloud.jazz.tools/?key=you@example.com" }}AccountSchema={
AccountSchema?: AccountSchema<{ root: CoMapSchema<{ todos: CoListSchema<CoMapSchema<{ title: ZodString; completed: ZodBoolean; }>>; }>; profile: CoMapSchema<...>; }> | undefined
MyAppAccount} > {
const MyAppAccount: AccountSchema<{ root: CoMapSchema<{ todos: CoListSchema<CoMapSchema<{ title: ZodString; completed: ZodBoolean; }>>; }>; profile: CoMapSchema<...>; }>
children: React.ReactNode
children} </function JazzReactProvider<S extends (AccountClass<Account> & CoValueFromRaw<Account>) | AnyAccountSchema>({ children, guestMode, sync, storage, AccountSchema, defaultProfileName, onLogOut, logOutReplacement, onAnonymousAccountDiscarded, enableSSR, }: JazzProviderProps<S>): JSX.Element
JazzReactProvider> ); }
Since the agent used is empty, all the useCoState
and useAccount
will return null.
If you want to render the data on the server you can use createSSRJazzAgent
to generate a read-only account to load the data:
import {
createSSRJazzAgent } from "jazz-tools/react/ssr"; import {
function createSSRJazzAgent(opts: { peer: string; }): import("/vercel/path0/packages/jazz-tools/dist/index").AnonymousJazzAgent
TodoItem } from "./schema"; // This can be created in a centralized module, to reuse the same agent in all the server components export const
const TodoItem: CoMapSchema<{ title: ZodString; completed: ZodBoolean; }>
const jazzSSR: AnonymousJazzAgent
jazzSSR =createSSRJazzAgent({
function createSSRJazzAgent(opts: { peer: string; }): import("/vercel/path0/packages/jazz-tools/dist/index").AnonymousJazzAgent
peer: string
peer: "wss://cloud.jazz.tools/", }); export default async functionServerSidePage(
function ServerSidePage(props: { params: Promise<{ itemId: string; }>; }): Promise<React.JSX.Element>
props: {
props: { params: Promise<{ itemId: string; }>; }
params:
params: Promise<{ itemId: string; }>
interface Promise<T>
Represents the completion of an asynchronous operationPromise<{itemId: string
itemId: string }>; }) { const {const itemId: string
itemId } = awaitprops.
props: { params: Promise<{ itemId: string; }>; }
params; const
params: Promise<{ itemId: string; }>
item = await
const item: ({ title: string; completed: boolean; } & CoMap) | null
TodoItem.
const TodoItem: CoMapSchema<{ title: ZodString; completed: ZodBoolean; }>
load(
load<true>(id: string, options?: { resolve?: RefsToResolve<{ title: string; completed: boolean; } & CoMap, 10, []> | undefined; loadAs?: Account | AnonymousJazzAgent; skipRetry?: boolean; } | undefined): Promise<...>
const itemId: string
itemId, {loadAs?: AnonymousJazzAgent | Account | undefined
loadAs:const jazzSSR: AnonymousJazzAgent
jazzSSR, }); return ( <React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>
divReact.HTMLAttributes<HTMLDivElement>.className?: string | undefined
className="flex flex-col items-center justify-center h-screen gap-4"> <React.JSX.IntrinsicElements.h1: React.DetailedHTMLProps<React.HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>
h1React.HTMLAttributes<T>.className?: string | undefined
className="text-2xl font-bold">SSR rendering example with Jazz</React.JSX.IntrinsicElements.h1: React.DetailedHTMLProps<React.HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>
h1> <React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>
divReact.HTMLAttributes<HTMLDivElement>.className?: string | undefined
className="text-sm text-gray-500 w-1/2 text-center"> This is a server component! </React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>
div> <React.JSX.IntrinsicElements.label: React.DetailedHTMLProps<React.LabelHTMLAttributes<HTMLLabelElement>, HTMLLabelElement>
label> <React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>
divReact.HTMLAttributes<HTMLDivElement>.className?: string | undefined
className="text-sm">Item title "{item?.
const item: ({ title: string; completed: boolean; } & CoMap) | null
title: string | undefined
title}"</React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>
div> </React.JSX.IntrinsicElements.label: React.DetailedHTMLProps<React.LabelHTMLAttributes<HTMLLabelElement>, HTMLLabelElement>
label> </React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>
div> ); }
Take a look on our Next.js example to see a complete example of how to use SSR with Jazz.
Further Reading
- Schemas - Learn about defining your data model
- Provider Configuration - Learn about other configuration options for Providers
- Authentication - Set up user authentication
- Sync and Storage - Learn about data persistence