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:

  1. Install dependencies
  2. Write your schema
  3. Wrap your app in <JazzProvider />

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-react jazz-tools

Write your schema

Define your data schema using CoValues from jazz-tools.

// schema.ts
import { import coco, import zz } from "jazz-tools";

export const 
const TodoItem: CoMapSchema<{
    title: z.z.ZodString;
    completed: z.z.ZodBoolean;
}>
TodoItem
= import coco.
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
map
({
title: z.z.ZodStringtitle: import zz.
function string(params?: string | z.z.core.$ZodStringParams): z.z.ZodString
export string
string
(),
completed: z.z.ZodBooleancompleted: import zz.
function boolean(params?: string | z.z.core.$ZodBooleanParams): z.z.ZodBoolean
export boolean
boolean
(),
}); export const
const AccountRoot: CoMapSchema<{
    todos: CoListSchema<CoMapSchema<{
        title: z.z.ZodString;
        completed: z.z.ZodBoolean;
    }>>;
}>
AccountRoot
= import coco.
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
map
({
todos: CoListSchema<CoMapSchema<{
    title: z.z.ZodString;
    completed: z.z.ZodBoolean;
}>>
todos
: import coco.
list<CoMapSchema<{
    title: z.z.ZodString;
    completed: z.z.ZodBoolean;
}>>(element: CoMapSchema<{
    title: z.z.ZodString;
    completed: z.z.ZodBoolean;
}>): CoListSchema<...>
export list
list
(
const TodoItem: CoMapSchema<{
    title: z.z.ZodString;
    completed: z.z.ZodBoolean;
}>
TodoItem
),
}); export const
const MyAppAccount: AccountSchema<{
    root: CoMapSchema<{
        todos: CoListSchema<CoMapSchema<{
            title: z.z.ZodString;
            completed: z.z.ZodBoolean;
        }>>;
    }>;
    profile: CoMapSchema<{
        name: z.z.ZodString;
    }>;
}>
MyAppAccount
= import coco.
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
account
({
root: CoMapSchema<{
    todos: CoListSchema<CoMapSchema<{
        title: z.z.ZodString;
        completed: z.z.ZodBoolean;
    }>>;
}>
root
:
const AccountRoot: CoMapSchema<{
    todos: CoListSchema<CoMapSchema<{
        title: z.z.ZodString;
        completed: z.z.ZodBoolean;
    }>>;
}>
AccountRoot
,
profile: CoMapSchema<{
    name: z.z.ZodString;
}>
profile
: import coco.
map<{
    name: z.z.ZodString;
}>(shape: {
    name: z.z.ZodString;
}): CoMapSchema<{
    name: z.z.ZodString;
}>
export map
map
({ name: z.z.ZodStringname: import zz.
function string(params?: string | z.z.core.$ZodStringParams): z.z.ZodString
export string
string
() }),
});

See CoValues for more information on how to define your schema.

Standard React Setup

Wrap your application with <JazzProvider /> to connect to the Jazz network and define your data schema:

// app.tsx
import { function JazzProvider<S extends (AccountClass<Account> & CoValueFromRaw<Account>) | AnyAccountSchema>({ children, guestMode, sync, storage, AccountSchema, defaultProfileName, onLogOut, logOutReplacement, onAnonymousAccountDiscarded, experimental_enableSSR, }: JazzProviderProps<S>): JSX.Element
@categoryContext & Hooks
JazzProvider
} from "jazz-react";
import {
const MyAppAccount: AccountSchema<{
    root: CoMapSchema<{
        todos: CoListSchema<CoMapSchema<{
            title: ZodString;
            completed: ZodBoolean;
        }>>;
    }>;
    profile: CoMapSchema<...>;
}>
MyAppAccount
} from "./schema";
function createRoot(container: Container, options?: RootOptions): Root
createRoot lets you create a root to display React components inside a browser DOM node.
@see{@link https://react.dev/reference/react-dom/client/createRoot API Reference for `createRoot`}
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.
@paramelementId String that specifies the ID value.
getElementById
("root")!).Root.render(children: React.ReactNode): voidrender(
<function JazzProvider<S extends (AccountClass<Account> & CoValueFromRaw<Account>) | AnyAccountSchema>({ children, guestMode, sync, storage, AccountSchema, defaultProfileName, onLogOut, logOutReplacement, onAnonymousAccountDiscarded, experimental_enableSSR, }: JazzProviderProps<S>): JSX.Element
@categoryContext & Hooks
JazzProvider
sync: SyncConfigsync={{ peer: "wss://cloud.jazz.tools/?key=you@example.com"peer: "wss://cloud.jazz.tools/?key=you@example.com" }}
AccountSchema?: AccountSchema<{
    root: CoMapSchema<{
        todos: CoListSchema<CoMapSchema<{
            title: ZodString;
            completed: ZodBoolean;
        }>>;
    }>;
    profile: CoMapSchema<...>;
}> | undefined
AccountSchema
={
const MyAppAccount: AccountSchema<{
    root: CoMapSchema<{
        todos: CoListSchema<CoMapSchema<{
            title: ZodString;
            completed: ZodBoolean;
        }>>;
    }>;
    profile: CoMapSchema<...>;
}>
MyAppAccount
}
> <function App(): React.JSX.ElementApp /> </function JazzProvider<S extends (AccountClass<Account> & CoValueFromRaw<Account>) | AnyAccountSchema>({ children, guestMode, sync, storage, AccountSchema, defaultProfileName, onLogOut, logOutReplacement, onAnonymousAccountDiscarded, experimental_enableSSR, }: JazzProviderProps<S>): JSX.Element
@categoryContext & Hooks
JazzProvider
>
);

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

Client-side Only (Easiest)

The simplest approach for Next.js is client-side only integration:

// @filename: schema.ts
import { co, z } from "jazz-tools";

export const TodoItem = co.map({
  title: z.string(),
  completed: z.boolean(),
});

export const AccountRoot = co.map({
  todos: co.list(TodoItem),
});

export const MyAppAccount = co.account({
  root: AccountRoot,
  profile: co.map({ name: z.string() }),
});
// @filename: app.tsx
import * as React from "react";
// ---cut---
// app.tsx
"use client" // Mark as client component

import { JazzProvider } from "jazz-react";
import { MyAppAccount } from "./schema";

export function JazzWrapper({ children }: { children: React.ReactNode }) {
  return (
    <JazzProvider
      sync={{ peer: "wss://cloud.jazz.tools/?key=you@example.com" }}
      AccountSchema={MyAppAccount}
    >
      {children}
    </JazzProvider>
  );
}

Remember to mark any component that uses Jazz hooks with "use client":

// Profile.tsx
"use client"; 

import { 
function useAccount<A extends AccountClass<Account> | AnyAccountSchema>(AccountSchema?: A): {
    me: Loaded<A, true>;
    logOut: () => void;
} (+1 overload)
useAccount
} from "jazz-react";
import {
const MyAppAccount: AccountSchema<{
    root: CoMapSchema<{
        todos: CoListSchema<CoMapSchema<{
            title: ZodString;
            completed: ZodBoolean;
        }>>;
    }>;
    profile: CoMapSchema<...>;
}>
MyAppAccount
} from "./schema";
export function function Profile(): React.JSX.ElementProfile() { const {
const me: ({
    profile: {
        name: string;
    } & CoMap & Profile;
} & {
    root: ({
        todos: CoList<({
            title: string;
            completed: boolean;
        } & CoMap) | null> | null;
    } & CoMap) | null;
    profile: ({
        name: string;
    } & CoMap) | null;
} & Account) | null | undefined
me
} =
useAccount<AccountSchema<{
    root: CoMapSchema<{
        todos: CoListSchema<CoMapSchema<{
            title: ZodString;
            completed: ZodBoolean;
        }>>;
    }>;
    profile: CoMapSchema<...>;
}>, {
    ...;
}>(AccountSchema: AccountSchema<...>, options?: {
    ...;
} | undefined): {
    ...;
} (+1 overload)
useAccount
(
const MyAppAccount: AccountSchema<{
    root: CoMapSchema<{
        todos: CoListSchema<CoMapSchema<{
            title: ZodString;
            completed: ZodBoolean;
        }>>;
    }>;
    profile: CoMapSchema<...>;
}>
MyAppAccount
, {
resolve?: RefsToResolve<{
    root: ({
        todos: CoList<({
            title: string;
            completed: boolean;
        } & CoMap) | null> | null;
    } & CoMap) | null;
    profile: ({
        name: string;
    } & CoMap) | null;
} & Account, 10, []> | undefined
resolve
: {
profile?: RefsToResolve<{
    name: string;
} & CoMap & Profile, 10, [0]> | undefined
profile
: true } });
return <JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>div>Hello, {
const me: ({
    profile: {
        name: string;
    } & CoMap & Profile;
} & {
    root: ({
        todos: CoList<({
            title: string;
            completed: boolean;
        } & CoMap) | null> | null;
    } & CoMap) | null;
    profile: ({
        name: string;
    } & CoMap) | null;
} & Account) | null | undefined
me
?.
Account.profile: {
    name: string;
} & CoMap & Profile
profile
.Profile.name: string | undefinedname}</JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>div>;
}

SSR Support (Experimental)

For server-side rendering, Jazz offers experimental approaches:

  • Pure SSR
  • Hybrid SSR + Client Hydration

Pure SSR

Use Jazz in server components by directly loading data with CoValue.load().

This works well for public data accessible to the server account.

Hybrid SSR + Client Hydration

For more complex cases, you can pre-render on the server and hydrate on the client:

  1. Create a shared rendering component.
  1. Create a client hydration component.
  1. Create a server component that pre-loads data.

This approach gives you the best of both worlds: fast initial loading with server rendering, plus real-time updates on the client.

Further Reading