Instant sync.

A new way to build apps with distributed state.
Cross-device sync
Real-time multiplayer
Team/social features
Built-in permissions
Cloud sync & storage
On-device storage
Instant UI updates
E2EE & signatures

Hard things are easy now.

Jazz is an open-source toolkit that replaces APIs, databases and message queues with a single new abstraction:

“Collaborative Values”distributed state with secure permissions built-in.

Features that used to take months to build now work out-of-the-box.

First impressions…

A chat app in 84 lines of code.
app.tsx
tsx
import { CoMap, CoList, co, Group, ID } from "jazz-tools";
import { createJazzReactContext, DemoAuth } from "jazz-react";
import { createRoot } from "react-dom/client";
import { useIframeHashRouter } from "hash-slash";
import { ChatScreen } from "./chatScreen.tsx";
 
export class Message extends CoMap {
text = co.string;
}
 
export class Chat extends CoList.Of(co.ref(Message)) {}
 
const Jazz = createJazzReactContext({
auth: DemoAuth({ appName: "Jazz Chat" }),
peer: `wss://mesh.jazz.tools/?key=you@example.com`
});
export const { useAccount, useCoState } = Jazz;
 
 
function App() {
const { me, logOut } = useAccount();
 
const createChat = () => {
const group = Group.create({ owner: me });
group.addMember("everyone", "writer");
const chat = Chat.create([], { owner: group });
location.hash = "/chat/" + chat.id;
};
 
return <div className="flex flex-col items-center justify-between w-screen h-screen p-2 dark:bg-black dark:text-white">
<div className="rounded mb-5 px-2 py-1 text-sm self-end">
{me.profile?.name} · <button onClick={logOut}>Log Out</button>
</div>
{useIframeHashRouter().route({
'/': () => createChat() as never,
'/chat/:id': (id) => <ChatScreen chatID={id as ID<Chat>} />
})}
</div>;
}
 
createRoot(document.getElementById("root")!)
.render(<Jazz.Provider><App/></Jazz.Provider>);
chatScreen.tsx
tsx
import { ID } from 'jazz-tools';
import { Chat, Message, useCoState } from './app.tsx';
 
export function ChatScreen(props: { chatID: ID<Chat> }) {
const chat = useCoState(Chat, props.chatID, [{}]);
 
return chat ? <div className='w-full max-w-xl h-full flex flex-col items-stretch'>
{chat.length > 0
? chat.map((msg) => <ChatBubble msg={msg} key={msg.id} />)
: <div className='m-auto text-sm'>(Empty chat)</div>}
<ChatInput onSubmit={(text) => {
chat.push(
Message.create({ text }, { owner: chat._owner })
);
}} />
</div> : <div>Loading...</div>;
}
 
function ChatBubble(props: { msg: Message }) {
const lastEdit = props.msg._edits.text;
const align = lastEdit.by?.isMe ? 'items-end' : 'items-start';
 
return <div className={`${align} flex flex-col`}>
<div className='rounded-xl bg-stone-100 dark:bg-stone-700 dark:text-white py-2 px-4 mt-2 min-w-[5rem]'>
{ props.msg.text }
</div>
<div className='text-xs text-neutral-500 ml-2'>
{ lastEdit.by?.profile?.name }{' '}
{ lastEdit.madeAt?.toLocaleTimeString() }
</div>
</div>;
}
 
function ChatInput(props: { onSubmit: (text: string) => void }) {
return <input className='rounded p-2 border mt-auto dark:bg-black dark:text-white border-stone-300 dark:border-stone-700'
placeholder='Type a message and press Enter'
onKeyDown={({ key, currentTarget: input }) => {
if (key !== 'Enter' || !input.value) return;
props.onSubmit(input.value);
input.value = '';
}} />;
}

Collaborative Values

Your new building blocks.

Based on CRDTs and public-key cryptography, CoValues...

  • Can be read & edited like simple local JSON state
  • Can be created anywhere, are automatically synced & persisted
  • Always keep full edit history & author metadata
  • Automatically resolve most conflicts

Bread-and-butter datastructures

CoMap

  • Collaborative key-value map - Possible values: - Immutable JSON & other CoValues

CoList

  • Collaborative ordered list - Possible items: - Immutable JSON & other CoValues

CoPlainText & CoRichText Coming soon

  • Collaborative plain-text & rich-text - Gracefully prevents most editing conflicts - Rendered as markdown, HTML, JSX, etc.

CoStream

  • Collection of independent per-user items streams:
    • Immutable JSON & other CoValues
  • Great for presence, reactions, polls, replies etc.

First-class files & binary data

BinaryCoStream

  • Represents a file or live binary stream - Can be referenced and synced like any other CoValue - Can easily be converted from/to browser Blobs
  • <input type="file"/> -> BinaryCoStream -> Blob -> BlobURL

ImageDefinition

  • Represents multiple resolutions of the same image - Can be progressively loaded, including super fast blur preview & image size info

Secure permissions, authorship & teams

Group

  • A scope where specified accounts have roles (reader/writer/admin).
  • A Group owns CoValues, with access right determined by group roles.
  • Accounts can be added to groups directly or using shareable invite secrets.

Account

  • Represents a single user and their signing/encryption keys.
  • Has a private account root and a public profile
    • Can contain arbitrary app-specific data

The Jazz Toolkit

A high-level toolkit for building apps around CoValues.

Supported environments:

  • Browser (sync via WebSockets, IndexedDB persistence)
    • React
    • Vanilla JS / framework agnostic base
  • React Native Coming soon
  • NodeJS (sync via WebSockets, SQLite persistence) Coming soon
  • Swift, Kotlin, Rust Coming later

Auto-sub

Let your UI drive data-syncing.
  • Load and auto-subscribe to deeply nested CoValues with a reactive hook (or callback). - Access properties & metadata as plain JSON. - Make granular changes with simple mutators. - No queries needed, everything loads on-demand:
    profile?.tweets?.map(tweet => tweet?.text)

Cursors & carets

Ready-made spatial presence.
  • 2D canvas cursors Coming soon
  • Text carets Coming soon
  • Element-based focus-presence Coming soon
  • Scroll-based / out-of-bounds helpers Coming soon

Auth Providers

Plug and play different kinds of auth.
  • DemoAuth (for quick multi-user demos)
  • WebAuthN (TouchID/FaceID)
  • Auth0, Clerk & Okta Coming soon
  • NextAuth Coming soon

Two-way sync to your DB

Add Jazz to an existing app.
  • Prisma Coming soon
  • Drizzle Coming soon
  • PostgreSQL introspection Coming soon

File upload & download

Just use <input type="file"/>.
  • Easily convert from and to Browser Blobs
  • Super simple progressive image loading

Video presence & calls

Stream and record audio & video.
  • Automatic WebRTC connections between Group members Coming soon
  • Audio/video recording into BinaryCoStreams Coming soon

Jazz Mesh

Serverless sync & storage for Jazz apps

To give you sync and secure collaborative data instantly on a global scale, we're running Jazz Mesh. It works with any Jazz-based app, requires no setup and has straightforward, scale-to-zero pricing.

Jazz Mesh is currently free — and it's set up as the default sync & storage peer in Jazz, letting you start building multi-user apps with persistence right away, no backend needed.

Learn more about Jazz Mesh

Get Started