With the right abstractions, you and your agents can make a lot of progress with a lot less code. Take a look at some of what's possible below.
P.S we made an Instant app just for you! Share this with your friends and you can play with every example together.
1import { id, init } from '@instantdb/react';23const db = init({4 appId: "__YOUR_APP_ID__",5});67export default function InstantTodos() {8 const { data, isLoading, error } = db.useQuery({ todos: {} });910 if (error) return <p className="p-4 text-red-500">Oops, something broke</p>;1112 return (13 <div className="mx-auto flex h-full max-w-md flex-col gap-4 px-4 pt-8">14 <h1 className="text-xl font-semibold tracking-tight text-gray-800">15 instado16 </h1>17 <form18 className="flex gap-2"19 onSubmit={(e) => {20 e.preventDefault();21 const input = e.currentTarget.elements.namedItem(22 'todo',23 ) as HTMLInputElement;24 if (!input.value) return;25 db.transact([26 db.tx.todos[id()].update({ text: input.value, completed: false }),27 ]);28 e.currentTarget.reset();29 }}30 >31 <input32 name="todo"33 type="text"34 placeholder="What needs to be done?"35 className="flex-1 rounded-lg border border-gray-200 px-3 py-2 text-sm outline-none focus:border-orange-400"36 />37 <button38 type="submit"39 className="rounded-lg bg-orange-600 px-4 py-2 text-sm font-medium text-white hover:bg-orange-700"40 >41 Add42 </button>43 </form>44 {data?.todos.length ? (45 <ul className="flex flex-col">46 {data.todos.map((todo) => (47 <li48 key={todo.id}49 className="group flex items-center gap-3 rounded-lg px-1 py-2 hover:bg-gray-50"50 >51 <input52 type="checkbox"53 className="accent-orange-600"54 checked={todo.completed}55 onChange={(e) =>56 db.transact([57 db.tx.todos[todo.id].update({58 completed: e.currentTarget.checked,59 }),60 ])61 }62 />63 <span64 className={`flex-1 text-sm ${todo.completed ? 'text-gray-300 line-through' : 'text-gray-700'}`}65 >66 {todo.text}67 </span>68 <button69 onClick={() => db.transact([db.tx.todos[todo.id].delete()])}70 className="text-gray-300 opacity-0 transition-opacity group-hover:opacity-100 hover:text-gray-500"71 >72 ×73 </button>74 </li>75 ))}76 </ul>77 ) : isLoading ? null : (78 <p className="text-sm text-gray-400 italic">79 No todos just yet! Create your first one :)80 </p>81 )}82 </div>83 );84}1import { Cursors, init } from '@instantdb/react';2import { useRef } from 'react';34const db = init({5 appId: "__YOUR_APP_ID__",6});78export default function InstantCursors() {9 const room = db.room('cursors-example', '123');10 const color = useRef(randomDarkColor()).current;11 return (12 <Cursors room={room} userCursorColor={color} className={cursorsClassNames}>13 <span className="text-sm text-gray-400 italic">14 Move your cursor around!15 </span>16 </Cursors>17 );18}1920function randomDarkColor() {21 return (22 '#' +23 [0, 0, 0]24 .map(() =>25 Math.floor(Math.random() * 200)26 .toString(16)27 .padStart(2, '0'),28 )29 .join('')30 );31}3233const cursorsClassNames = [34 'flex h-full w-full items-center justify-center overflow-hidden touch-none',35 'bg-white',36 'bg-[radial-gradient(circle,#e0ddd5_1px,transparent_1px)]',37 'bg-[length:24px_24px]',38].join(' ');1import { Cursors, id, init } from '@instantdb/react';2import { useRef } from 'react';34const db = init({5 appId: "__YOUR_APP_ID__",6});78function CustomCursor({ name }: { name: string }) {9 return (10 <img11 src={`https://instantdb.com/api/avatar?name=${encodeURIComponent(name)}&size=40`}12 width={40}13 height={40}14 loading="eager"15 decoding="async"16 alt=""17 className="h-10 w-10"18 />19 );20}2122export default function InstantCursors() {23 const room = db.room('cursors-example', '124');24 const userId = useRef(id()).current;25 const color = useRef(randomDarkColor()).current;2627 db.rooms.useSyncPresence(room, {28 name: userId,29 });3031 return (32 <Cursors33 room={room}34 renderCursor={(props) => <CustomCursor name={props.presence.name} />}35 userCursorColor={color}36 className={cursorsClassNames}37 >38 <span className="text-sm text-gray-400 italic">39 You can customize your cursors too!40 </span>41 </Cursors>42 );43}4445function randomDarkColor() {46 return (47 '#' +48 [0, 0, 0]49 .map(() =>50 Math.floor(Math.random() * 200)51 .toString(16)52 .padStart(2, '0'),53 )54 .join('')55 );56}5758const cursorsClassNames = [59 'flex h-full w-full items-center justify-center overflow-hidden',60 'bg-white',61 'bg-[radial-gradient(circle,#e0ddd5_1px,transparent_1px)]',62 'bg-[length:24px_24px]',63].join(' ');1import { RefObject, createRef, useRef } from 'react';2import { init } from '@instantdb/react';34const db = init({5 appId: "__YOUR_APP_ID__",6});78export default function InstantTopics() {9 const room = db.room('topics-example', '123');10 const publishEmoji = db.rooms.usePublishTopic(room, 'emoji');1112 db.rooms.useTopicEffect(13 room,14 'emoji',15 ({ name, directionAngle, rotationAngle }) => {16 const emojiName = name as EmojiName;17 if (!emoji[emojiName]) return;1819 animateEmoji(20 { emoji: emoji[emojiName], directionAngle, rotationAngle },21 elRefsRef.current[name].current,22 );23 },24 );2526 const elRefsRef = useRef<{27 [k: string]: RefObject<HTMLDivElement>;28 }>(refsInit());2930 return (31 <div className={containerClassNames}>32 <div className="flex gap-4">33 {emojiNames.map((name) => (34 <div className="relative" key={name} ref={elRefsRef.current[name]}>35 <button36 className={emojiButtonClassNames}37 onClick={() => {38 const params = {39 name,40 rotationAngle: Math.random() * 360,41 directionAngle: Math.random() * 360,42 };43 animateEmoji(44 {45 emoji: emoji[name],46 rotationAngle: params.rotationAngle,47 directionAngle: params.directionAngle,48 },49 elRefsRef.current[name].current,50 );5152 publishEmoji(params);53 }}54 >55 {emoji[name]}56 </button>57 </div>58 ))}59 </div>60 </div>61 );62}6364type EmojiName = keyof typeof emoji;6566const emoji = {67 fire: '🔥',68 wave: '👋',69 confetti: '🎉',70 heart: '❤️',71} as const;7273const emojiNames = Object.keys(emoji) as EmojiName[];7475function refsInit() {76 return Object.fromEntries(77 emojiNames.map((name) => [name, createRef<HTMLDivElement>()]),78 );79}8081const containerClassNames = [82 'flex h-full w-full items-center justify-center overflow-hidden select-none',83 'bg-[radial-gradient(circle,#e0ddd5_1px,transparent_1px)]',84 'bg-[length:24px_24px]',85].join(' ');8687const emojiButtonClassNames =88 'rounded-xl bg-white p-3 text-3xl shadow-md ring-1 ring-gray-100 transition duration-200 ease-in-out hover:-translate-y-1 hover:shadow-xl active:scale-95';8990function animateEmoji(91 config: { emoji: string; directionAngle: number; rotationAngle: number },92 target: HTMLDivElement | null,93) {94 if (!target) return;9596 const rootEl = document.createElement('div');97 const directionEl = document.createElement('div');98 const spinEl = document.createElement('div');99100 spinEl.innerText = config.emoji;101 directionEl.appendChild(spinEl);102 rootEl.appendChild(directionEl);103 target.appendChild(rootEl);104105 style(rootEl, {106 transform: `rotate(${config.directionAngle * 360}deg)`,107 position: 'absolute',108 top: '0',109 left: '0',110 right: '0',111 bottom: '0',112 margin: 'auto',113 zIndex: '9999',114 pointerEvents: 'none',115 });116117 style(spinEl, {118 transform: `rotateZ(${config.rotationAngle * 400}deg)`,119 fontSize: `40px`,120 });121122 setTimeout(() => {123 style(directionEl, {124 transform: `translateY(40vh) scale(2)`,125 transition: 'all 400ms',126 opacity: '0',127 });128 }, 20);129130 setTimeout(() => rootEl.remove(), 800);131}132133function style(el: HTMLElement, styles: Partial<CSSStyleDeclaration>) {134 Object.assign(el.style, styles);135}1import { id, init } from '@instantdb/react';2import { useRef } from 'react';34const db = init({5 appId: "__YOUR_APP_ID__",6});78export default function InstantTypingIndicator() {9 const room = db.room('typing-indicator-example', '1234');10 const userId = useRef(id()).current;11 db.rooms.useSyncPresence(room, { id: userId });1213 const presence = db.rooms.usePresence(room);14 const { active, inputProps } = db.rooms.useTypingIndicator(15 room,16 'chat-input',17 );1819 const peers = Object.values(presence.peers);20 const activeSet = new Set(active.map((p) => p.id));2122 return (23 <div className="flex h-full">24 <div className="flex w-12 flex-col items-center gap-2 border-r border-gray-100 py-3">25 {peers.map((peer) => (26 <div key={peer.id} className="relative">27 <img28 src={`https://instantdb.com/api/avatar?name=${encodeURIComponent(peer.id || '')}&size=32`}29 alt=""30 className="h-8 w-8 rounded-full"31 />32 {activeSet.has(peer.id) ? (33 <div className="absolute -right-1 bottom-0 rounded-xs bg-black px-1 text-[10px] leading-3 text-white">34 ⋯35 </div>36 ) : null}37 </div>38 ))}39 </div>40 <div className="flex flex-1 flex-col">41 <div className="flex flex-1 items-center justify-center">42 <p className="text-sm text-gray-400 italic">43 Start typing to see the indicator!44 </p>45 </div>46 <div className="px-3 pt-1 pb-3">47 <div className="truncate text-xs text-gray-500">48 {active.length ? typingInfo(active) : <> </>}49 </div>50 <textarea51 placeholder="Write a message..."52 className="w-full resize-none rounded-lg border border-gray-200 px-3 py-2 text-sm outline-none focus:border-orange-400"53 rows={1}54 onKeyDown={(e) => inputProps.onKeyDown(e)}55 onBlur={() => inputProps.onBlur()}56 />57 </div>58 </div>59 </div>60 );61}6263function typingInfo(active: unknown[]) {64 if (active.length === 1) return '1 person is typing...';65 return `${active.length} people are typing...`;66}1import { id, init } from '@instantdb/react';2import { useRef } from 'react';34const db = init({5 appId: "__YOUR_APP_ID__",6});78export default function InstantAvatarStack() {9 const room = db.room('avatars-example', 'avatars-example-1234');10 const userId = useRef(id()).current;1112 const presence = room.usePresence({ user: true });13 db.rooms.useSyncPresence(room, { name: userId.slice(0, 6) });1415 const peerCount = Object.keys(presence.peers).length;1617 return (18 <div className="flex h-full items-center justify-center px-4">19 <div className="flex flex-col gap-2">20 <div className="text-xs font-semibold tracking-wide text-gray-400 uppercase">21 Online — {peerCount + 1}22 </div>23 {presence.user ? <AvatarRow name={presence.user.name} /> : null}24 {Object.entries(presence.peers).map(([peerId, peer]) => (25 <AvatarRow key={peerId} name={peer.name} />26 ))}27 <p className="mt-1 text-xs text-gray-400 italic">28 Add more previews to see more avatars!29 </p>30 </div>31 </div>32 );33}3435function AvatarRow({ name }: { name: string }) {36 return (37 <div className="flex items-center gap-2.5">38 <div className="relative">39 <img40 src={`https://instantdb.com/api/avatar?name=${encodeURIComponent(name)}&size=32`}41 alt={name}42 className="h-8 w-8 rounded-full"43 />44 <div className="absolute -right-0.5 -bottom-0.5 h-3 w-3 rounded-full border-2 border-white bg-green-500" />45 </div>46 <span className="text-sm font-medium text-gray-700">{name}</span>47 </div>48 );49}1/*2 * Tile Game!3 * This example is meant to mimic a simple collaborative game. We use a 4x4 grid4 * that users can color. We use `merge` to update a slice of data without5 * overwriting potential changes from other clients.6 * */78import { useEffect, useState } from 'react';9import { init } from '@instantdb/react';1011const db = init({12 appId: "__YOUR_APP_ID__",13});1415export default function App() {16 const room = db.room('tile-game-example');17 const [myColor, setMyColor] = useState<string | null>(null);18 const { isLoading, error, data } = db.useQuery({19 boards: { $: { where: { id: boardId } } },20 });21 const {22 peers,23 publishPresence,24 isLoading: isPresenceLoading,25 } = db.rooms.usePresence(room);2627 const boardState = data?.boards[0]?.state;2829 useEffect(() => {30 if (isLoading || isPresenceLoading || error) return;3132 // If the board doesn't exist, create it33 if (!boardState) {34 db.transact([db.tx.boards[boardId].update({ state: makeEmptyBoard() })]);35 }3637 // If I don't have a color, generate one and publish it38 // make sure to not choose a color that a peer has already chosen39 if (!myColor) {40 const takenColors = new Set(Object.values(peers).map((p) => p.color));41 const available = colors.filter((c) => !takenColors.has(c));42 const color =43 available[Math.floor(Math.random() * available.length)] || colors[0];44 setMyColor(color);45 publishPresence({ color });46 }47 }, [isLoading, isPresenceLoading, error, boardState]);4849 if (error)50 return <div className="p-4 text-sm text-red-500">{error.message}</div>;51 if (!boardState || isLoading || isPresenceLoading) return null;5253 return (54 <div className="flex h-full flex-col items-center justify-center gap-4 bg-[radial-gradient(circle,#e0ddd5_1px,transparent_1px)] bg-[length:24px_24px] p-4">55 {/* Header */}56 <div className="flex w-full max-w-[200px] items-center justify-between">57 <div className="flex items-center gap-2">58 <div59 className="h-3 w-3 rounded-full"60 style={{ backgroundColor: myColor ?? '#ddd' }}61 />62 <span className="text-xs text-gray-500">Your color</span>63 </div>64 <button65 className="text-xs text-gray-400 hover:text-gray-600"66 onClick={() => {67 db.transact([68 db.tx.boards[boardId].update({ state: makeEmptyBoard() }),69 ]);70 }}71 >72 Reset73 </button>74 </div>7576 {/* Board */}77 <div className="grid grid-cols-4 gap-1 rounded-xl border border-gray-200 bg-white p-2 shadow-sm">78 {Array.from({ length: boardSize }).map((_, r) =>79 Array.from({ length: boardSize }).map((_, c) => {80 const key = `${r}-${c}`;81 return (82 <div83 key={key}84 className="h-11 w-11 cursor-pointer rounded-lg transition-colors hover:brightness-95"85 style={{86 backgroundColor: boardState[key] || emptyColor,87 }}88 onClick={() => {89 db.transact([90 db.tx.boards[boardId].merge({91 state: { [key]: myColor },92 }),93 ]);94 }}95 />96 );97 }),98 )}99 </div>100 </div>101 );102}103104const boardSize = 4;105const emptyColor = '#f5f3f0';106107const colors = [108 '#e76f51', // warm red109 '#2a9d8f', // teal110 '#e9c46a', // amber111 '#264653', // dark teal112 '#f4a261', // orange113 '#d4a0d0', // lavender114];115116const boardId = '83c059e2-ed47-42e5-bdd9-6de88d26c521';117118function makeEmptyBoard() {119 const board: Record<string, string> = {};120 for (let r = 0; r < boardSize; r++) {121 for (let c = 0; c < boardSize; c++) {122 board[`${r}-${c}`] = emptyColor;123 }124 }125 return board;126}1import { useState } from 'react';2import { init } from '@instantdb/react';34const db = init({5 appId: "__YOUR_APP_ID__",6});78export default function InstantAuth() {910 return (11 <div className={cls.root}>12 <db.SignedIn>13 <Dashboard />14 </db.SignedIn>15 <db.SignedOut>16 <Login />17 </db.SignedOut>18 </div>19 );20}2122function Dashboard() {23 const user = db.useUser();2425 return (26 <div className={cls.card}>27 <h2 className={cls.heading}>Welcome!</h2>28 <p className={cls.description}>29 You are signed in as <strong>{user.email}</strong>30 </p>31 <button className={cls.secondaryButton} onClick={() => db.auth.signOut()}>32 Sign Out33 </button>34 </div>35 );36}3738function Login() {39 const [state, setState] = useState({40 sentEmail: '',41 email: '',42 code: '',43 error: '',44 });4546 const { sentEmail, email, code, error } = state;4748 if (!sentEmail) {49 return (50 <form51 className={cls.card}52 onSubmit={async (e) => {53 e.preventDefault();54 if (!email) return;55 setState({ ...state, sentEmail: email, error: '' });56 try {57 await db.auth.sendMagicCode({ email });58 } catch (err: any) {59 setState({ ...state, sentEmail: '', error: err.body?.message });60 }61 }}62 >63 <h2 className={cls.heading}>Let's log you in</h2>64 <p className={cls.description}>65 Enter your email and we'll send you a verification code.66 </p>67 <input68 className={cls.input}69 placeholder="Enter your email"70 type="email"71 value={email}72 onChange={(e) =>73 setState({ ...state, email: e.target.value, error: '' })74 }75 />76 <button type="submit" className={cls.button} disabled={!email.trim()}>77 Send Code78 </button>79 {error ? <p className={cls.error}>{error}</p> : null}80 </form>81 );82 }8384 return (85 <form86 className={cls.card}87 onSubmit={async (e) => {88 e.preventDefault();89 if (!code) return;90 try {91 await db.auth.signInWithMagicCode({ email: sentEmail, code });92 } catch (err: any) {93 setState({ ...state, error: err.body?.message });94 }95 }}96 >97 <h2 className={cls.heading}>Enter your code</h2>98 <p className={cls.description}>99 We sent a code to <strong>{sentEmail}</strong>100 </p>101 <input102 autoFocus103 className={cls.input}104 type="text"105 inputMode="numeric"106 placeholder="Verification code"107 value={code}108 onChange={(e) =>109 setState({ ...state, code: e.target.value, error: '' })110 }111 />112 <button type="submit" className={cls.button} disabled={!code.trim()}>113 Verify Code114 </button>115 <button116 type="button"117 className={cls.secondaryButton}118 onClick={() =>119 setState({ sentEmail: '', email: '', code: '', error: '' })120 }121 >122 Back123 </button>124 {error ? <p className={cls.error}>{error}</p> : null}125 </form>126 );127}128129const cls = {130 root: 'flex h-full items-center justify-center px-2',131 card: 'flex w-full max-w-xs flex-col gap-3',132 heading: 'text-lg font-bold',133 description: 'text-sm text-gray-600',134 input:135 'rounded-lg border border-gray-200 px-3 py-2 text-sm outline-none focus:border-orange-400 w-full',136 button:137 'rounded-lg bg-orange-600 px-4 py-2 text-sm font-medium text-white hover:bg-orange-700 w-full disabled:opacity-50',138 secondaryButton:139 'rounded-lg border border-gray-200 px-4 py-2 text-sm font-medium text-gray-700 hover:bg-gray-50 w-full',140 error: 'text-red-700 text-sm bg-red-50 border border-red-500 rounded-sm p-2',141};