## File: README.md

If you had a database on the client, you wouldn't need to think about stores, selectors, endpoints, or local caches: just write queries. If these queries were multiplayer by default, you wouldn't have to worry about stateful servers. And if your database supported rollback, you'd get optimistic updates for free.

So we built Instant. Instant gives you a database you can use in the client, so you can focus on what’s important: building a great UX for your users, and doing it quickly.

## Architectural Overview

Here's how Instant works at a high level:



Under the hood, we store all user data as triples in one big Postgres database. A multi-tenant setup lets us offer a free tier that never pauses.

A sync server written in Clojure talks to Postgres. We wrote a query engine that understands datalog and [InstaQL](https://www.instantdb.com/docs/instaql), a relational language that looks a lot like GraphQL:

```javascript
// give me all users, their posts and comments
{
  users: {
    posts: {
      comments: {
      }
    }
  }
}
```

Taking inspiration from [Asana’s WorldStore](https://asana.com/inside-asana/worldstore-distributed-caching-reactivity-part-1) and [Figma’s LiveGraph](https://www.figma.com/blog/how-figmas-multiplayer-technology-works/#syncing-object-properties), we tail postgres’ WAL to detect novelty and invalidate relevant queries.

For the frontend, we wrote a client-side triple store. The SDK handles persisting a cache of recent queries to IndexedDB on web, and AsyncStorage in React Native.

All data goes through a permission system powered by Google's [CEL library](https://github.com/google/cel-java).

## Getting Started

The easiest way to get started with Instant is by signing up on [instantdb.com](https://instantdb.com). [You can create a functional app in 5 minutes or less](https://instantdb.com/docs).

If you have any questions, you can jump in on our [discord](https://discord.com/invite/VU53p7uQcE).

## Contributing

You can start by joining our [discord](https://discord.com/invite/VU53p7uQcE) and introducing yourself. Even if you don't contribute code, we always love feedback.

If you want to make changes, start by reading the [`client`](./client/) and [`server`](./server/) READMEs. There you'll find instructions to start Instant locally.

---

## File: client/packages/react-native/README.md

[Get Started](https://www.instantdb.com/docs/start-rn) ·
   [Examples](https://instantdb.com/examples) ·
   [Docs](https://www.instantdb.com/docs/start-rn) ·
   [Discord](https://discord.com/invite/VU53p7uQcE)


Welcome to [Instant's](http://instantdb.com) React Native SDK.

```javascript
// ༼ つ ◕_◕ ༽つ Real-time Chat
// ----------------------------------
// * Updates instantly
// * Multiplayer
// * Works offline

import { init, id } from '@instantdb/react-native';

const db = init({
  appId: process.env.NEXT_PUBLIC_APP_ID,
});

function Chat() {
  // 1. Read
  const { isLoading, error, data } = db.useQuery({
    messages: {},
  });

  // 2. Write
  const addMessage = (message) => {
    db.transact(db.tx.messages[id()].update(message));
  };

  // 3. Render!
  return ;
}
```

# Get Started

Follow the [getting started](https://www.instantdb.com/docs/start-rn) tutorial to set up a live React Native app in under 5 minutes!

# Questions?

If you have any questions, feel free to drop us a line on our [Discord](https://discord.com/invite/VU53p7uQcE)

---

## File: client/packages/react/README.md

[Get Started](https://instantdb.com/dash) ·
   [Examples](https://instantdb.com/examples) ·
   [Docs](https://instantdb.com/docs) ·
   [Discord](https://discord.com/invite/VU53p7uQcE)


Welcome to [Instant's](http://instantdb.com) React SDK.

```javascript
// ༼ つ ◕_◕ ༽つ Real-time Chat
// ----------------------------------
// * Updates instantly
// * Multiplayer
// * Works offline

import { init, id } from '@instantdb/react';

const db = init({
  appId: process.env.NEXT_PUBLIC_APP_ID,
});

function Chat() {
  // 1. Read
  const { isLoading, error, data } = db.useQuery({
    messages: {},
  });

  // 2. Write
  const addMessage = (message) => {
    db.transact(db.tx.messages[id()].update(message));
  };

  // 3. Render!
  return ;
}
```

# Get Started

Follow the [getting started](https://www.instantdb.com/docs) tutorial to set up a live React app in under 5 minutes!

# Questions?

If you have any questions, feel free to drop us a line on our [Discord](https://discord.com/invite/VU53p7uQcE)

---

## File: client/packages/platform/README.md

[Get Started](https://www.instantdb.com/docs/backend) ·
   [Examples](https://instantdb.com/examples) ·
   [Docs](https://www.instantdb.com/docs/backend) ·
   [Discord](https://discord.com/invite/VU53p7uQcE)


Welcome to [Instant's](http://instantdb.com) platform SDK.

The Platform SDK allows you to manage apps on behalf of an Instant user.

# Usage

## OAuth flow

You'll need an OAuth access token to make request on the Instant user's behalf. The platform SDK includes helpers for performing the OAuth flow in the `OAuthHandler` class.

Go to the [OAuth Apps page of the dashboard](https://www.instantdb.com/dash?s=main&t=oauth-apps) to create a new OAuth client id.

First you'll need to create a page that you can redirect to complete the OAuth flow. It should live on the same domain as the page where you're originating the OAuth flow:

```tsx
// oauth/instant/redirect.tsx
import { OAuthHandler } from '@instantdb/platform';
import { useEffect } from 'react';

const oauthHandler = new OAuthHandler({
  // https://www.instantdb.com/dash?s=main&t=oauth-apps
  clientId: 'YOUR_CLIENT_ID',
  // Be sure the redirectUri matches one of the authorized redirect uris
  // in your OAuth App client config on the Instant dashboard.
  redirectUri: 'https://example.com/oauth/instant/redirect',
});

export default function Page() {
  useEffect(() => {
    // This will send the oauth code to the originating window,
    // then close the window.
    return oauthHandler.handleClientRedirect();
  });

  return Loading...;
}
```

On the page where you want the user to connect:

```tsx
// ConnectPage.tsx
import { OAuthHandler } from '@instantdb/platform';

// Available scopes are: apps-read, apps-write,
//                       data-read, data-write,
//                       storage-read, storage-write
const scopes = ['apps-write'];

const handler = new OAuthHandler({
  // https://www.instantdb.com/dash?s=main&t=oauth-apps
  clientId: 'YOUR_CLIENT_ID',
  // Be sure the redirectUri matches one of the authorized redirect uris
  // in your OAuth App client config on the Instant dashboard.
  redirectUri: 'https://example.com/oauth/instant/redirect',
});

export default function Page() {
  const handleConnect = async () => {
    try {
      // This will open a new window where the user will complete the OAuth flow
      const token = await oauthHandler.startClientOnlyFlow(scopes);
      // doSomethingWith(token)
    } catch (e) {
      alert(e.message);
    }
  };

  return (
    Connect to your Instant Account
  );
}
```

The client-only flow described here uses PKCE and does not support refresh tokens. For a server-based flow that supports refresh tokens, see the [Platform OAuth docs](https://www.instantdb.com/docs/auth/platform-oauth).

## Making API requests

Once you have your token, you can perform actions on the user's behalf with the `PlatformApi` class.

Setup:

```js
import { PlatformApi } from '@instantdb/platform';

const api = new PlatformApi({ auth: { token: 'OAUTH_ACCESS_TOKEN' } });
```

### getApps

Requires the `apps-read` or `apps-write` scope.

Get all of the user's apps, optionally fetching the schema and permissions:

```js
const { apps } = await api.getApps({ includeSchema: true, includePerms: true });
```

### getApp

Requires the `apps-read` or `apps-write` scope.

Get an app by its id, optionally fetching the schema and permissions:

```js
const { app } = await api.getApp(YOUR_APP_ID, {
  includeSchema: true,
  includePerms: true,
});
```

### getSchema

Requires the `apps-read` or `apps-write` scope.

Get the schema for an app by its id:

```ts
const { schema } = await api.getSchema(YOUR_APP_ID);
```

The Platform SDK includes a helper for generating the `instant.schema.ts` file from the schema returned by the API.

```ts
import { generateSchemaTypescriptFile } from '@instantdb/platform';

// Generate the instant.schema.ts file with:
const schemaTs = generateSchemaTypescriptFile(null, schema, '@instantdb/react');
```

### getPerms

Requires the `apps-read` or `apps-write` scope.

Get the permissions for an app by its id:

```ts
const { perms } = await api.getPerms(YOUR_APP_ID);
```

The Platform SDK includes a helper for generating the `instant.perms.ts` file from the perms returned by the API.

```ts
import { generatePermsTypescriptFile } from '@instantdb/platform';

// Generate the instant.schema.ts file with:
const permsTs = generatePermsTypescriptFile(perms, '@instantdb/react');
```

### createApp

Requires the `apps-write` scope.

Create a new app in the authenticated user's account:

```ts
const { app } = await api.createApp({ title: 'Great new app' });
```

`createApp` takes optional `schema` and `perms` arguments.

Create an app with permissions:

```ts
import type { InstantRules } from '@instantdb/platform';

const perms: InstantRules = {
  $default: {
    allow: {
      $default: false,
    },
  },
  todos: {
    allow: {
      view: 'true',
      create: 'isOwner',
      update: 'isOwner',
      delete: 'isOwner',
    },
    bind: { isOwner: 'auth.id != null && auth.id == data.creatorId' },
  },
};

const { app } = await api.createApp({
  title: 'My app with permissions',
  perms: perms,
});
```

Create an app with a schema:

```ts
import { i } from '@instantdb/platform';

const schema = i.schema({
  entities: {
    todos: i.entity({
      title: i.string(),
      done: i.boolean(),
    }),
  },
});

const { app } = await api.createApp({
  title: 'Todo app',
  schema: schema,
});
```

### updateApp

Requires the `apps-write` scope.

Update an app's title by its id:

```ts
const { app } = await api.updateApp(YOUR_APP_ID, { title: 'New app title' });
```

### deleteApp

Requires the `apps-write` scope.

Delete an app by its id:

```ts
const { app } = await api.deleteApp(YOUR_APP_ID);
```

### pushPerms

Requires the `apps-write` scope.

Update the permissions for an app by its id. This will completely replace the current set of permissions.

```ts
import type { InstantRules } from '@instantdb/platform';

const perms: InstantRules = {
  $default: {
    allow: {
      $default: false,
    },
  },
  todos: {
    allow: {
      view: 'true',
      create: 'isOwner',
      update: 'isOwner',
      delete: 'isOwner',
    },
    bind: { isOwner: 'auth.id != null && auth.id == data.creatorId' },
  },
};

const { app } = await api.pushPerms(YOUR_APP_ID, {
  perms: perms,
});
```

### planSchemaPush

Requires the `apps-read` or `apps-write` scope.

Performs a dry-run of `schemaPush`, returning the steps that would be taken.

```ts
import { i } from '@instantdb/platform';

const schema = i.schema({
  entities: {
    todos: i.entity({
      title: i.string().indexed(),
      done: i.boolean(),
      completedAt: i.date().optional(),
    }),
  },
});

const { steps } = await api.planSchemaPush(YOUR_APP_ID, { schema: schema });

// Or, to allow deletions and renames:
const { steps } = await api.planSchemaPush(YOUR_APP_ID, {
  schema: schema,
  overwrite: true,
  renames: ['todos.name:todos.title'],
});

// steps
// [
//   { type: 'index', friendlyDescription: 'Add index to todos.title.' },
//   {
//     type: 'add-attr',
//     friendlyDescription: 'Add attribute todos.completedAt.',
//     attr: {...},
//   },
// ];
```

### schemaPush

Requires the `apps-write` scope.

Push a new schema to an app.

Some schema updates, like adding an index to an attribute with existing data, kick off a process that completes in the background. The `schemaPush` method will wait for all of the background processes to finish before it returns.

You can subscribe to progress updates to display feedback to the user.

```ts
import { i } from '@instantdb/platform';

const schema = i.schema({
  entities: {
    todos: i.entity({
      title: i.string().indexed(),
      done: i.boolean(),
      completedAt: i.date().optional(),
    }),
  },
});

const pushPromise = api.schemaPush(YOUR_APP_ID, { schema: schema });

// Or, to allow deletions and renames:
const { steps } = await api.planSchemaPush(YOUR_APP_ID, {
  schema: schema,
  overwrite: true,
  renames: ['todos.name:todos.title'],
});

pushPromise.subscribe({
  next(status) {
    console.log(status.friendlyDescription);
  },
});

const { steps } = await pushPromise;
```

Note that the promise will return the steps without throwing even if some of the background steps failed. For example, if an attribute was marked `unique`, but there were multiple entities with the same value. In the case of failure, the step will have a `backgroundJob` field where `error` is set to a string.

Here is an example of a failed step to make the title attribute unique because mulitple entities had the same `Write docs` value.

```ts
// steps
[
  {
    type: 'unique',
    friendlyDescription: 'Ensure that todos.title is unique.',
    attrId: '07145112-59b6-4617-9abc-544a3c3e146c',
    forwardIdentity: ['24c6c019-97ef-4915-aef5-7f4f09b372e1', 'todos', 'title'],
    backgroundJob: {
      id: '1a5941ad-542b-4d0a-bce8-81ced3eaed1a',
      createdAt: '2025-05-30T23:26:54.000Z',
      updatedAt: '2025-05-30T23:26:54.000Z',
      status: 'errored',
      workEstimate: 2,
      workCompleted: null,
      error: 'triple-not-unique-error',
      invalidTriplesSample: [
        {
          entityId: 'b59b3be0-9d76-419f-8f95-e28830d12a40',
          value: 'Write docs',
          jsonType: 'string',
        },
        {
          entityId: 'eb57dbc8-5e09-4978-b255-1b81ff46b63e',
          value: 'Write docs',
          jsonType: 'string',
        },
      ],
      type: 'unique',
      invalidUniqueValue: 'Write docs',
    },
  },
];
```

Some failed steps will include an `invalidTriplesSample` in the background job, which show some of the triples that caused the error.

## Managing schemas

The platform package includes helpers for generating the `instant.schema.ts` and `instant.perms.ts` config files from the schema and perms data returned from the API.

```ts
import {
  generateSchemaTypescriptFile,
  generatePermsTypescriptFile,
} from '@instantdb/platform';

console.log(
  generateSchemaTypescriptFile(null, shemaFromApi, '@instantdb/core'),
);

console.log(generatePermsTypescriptFile(permsFromApi, '@instantdb/core'));
```

Use `schemaTypescriptFileToInstantSchema` to recover an `InstantSchemaDef` from the typescript file:

```ts
import {
  i,
  generateSchemaTypescriptFile,
  schemaTypescriptFileToInstantSchema,
} from '@instantdb/platform';

// Example schema
const schema = i.schema({
  entities: {
    books: i.entity({
      title: i.string().unique(),
    }),
  },
});

// Example of the typescript file that was generated for a schema
const code = generateTypescriptFile(null, schema, '@instantdb/core');

const recoveredSchema = schemaTypescriptFileToInstantSchema(code);

schema == recoveredSchema;
```

This is useful when parsing a schema that the user manually edited or pulled with `npx instant-cli pull`.

# Questions?

If you have any questions, feel free to drop us a line on our [Discord](https://discord.com/invite/VU53p7uQcE)

---

## File: client/packages/core/README.md

[Get Started](https://www.instantdb.com/docs/start-vanilla) ·
   [Examples](https://instantdb.com/examples) ·
   [Docs](https://www.instantdb.com/docs/start-vanilla) ·
   [Discord](https://discord.com/invite/VU53p7uQcE)


Welcome to [Instant's](http://instantdb.com) vanilla javascript SDK.

```javascript
db.subscribeQuery({ todos: {} }, (resp) => {
  if (resp.error) {
    renderError(resp.error.message);
    return;
  }
  if (resp.data) {
    render(resp.data); // wohoo!
  }
});
```

# Get Started

Follow the [getting started in vanilla Javascript](https://www.instantdb.com/docs/start-vanilla) tutorial to set up a live app in under 5 minutes!

# Questions?

If you have any questions, feel free to drop us a line on our [Discord](https://discord.com/invite/VU53p7uQcE)

---

## File: client/packages/cli/README.md

[Get Started](https://www.instantdb.com/docs/start-vanilla) ·
   [Examples](https://instantdb.com/examples) ·
   [Docs](https://www.instantdb.com/docs/start-vanilla) ·
   [Discord](https://discord.com/invite/VU53p7uQcE)


Welcome to [Instant's](http://instantdb.com) command line tool. You can create apps, write schema, and push permissions.

```javascript
npx instant-cli init
```

## Get Started

Start by peeking at the [instant-cli docs](https://www.instantdb.com/docs/cli).

# Contributing

Here's how to set up a local development environment for instant-cli.

## Quick Start

```bash
Clone this repo
git clone ..

# If you made any backend changes, run the server locally in a separate terminal
cd server
make dev

# Add --filter instant-cli to the 'dev' script in client/package.json to include
# instant-cli in the dev process
"dev": "turbo run dev ... --filter instant-cli"

# Now run the client to listen to cli changes
cd client
make dev

# Now go into a place where you can test out the CLI in your terminal
cd client/sandbox/cli-nodejs
INSTANT_CLI_DEV=1 npx instant-cli ...
```

## Testing local builds

You can link a local build of `instant-cli` globally so it's available as a regular command:

```bash
cd client/packages/cli
pnpm build
pnpm link --global
which instant-cli # should point to your pnpm global bin dir
```

Now you can run `instant-cli` anywhere and it will use your local build.

To unlink:

```bash
pnpm unlink --global instant-cli
```

# Questions?

If you have any questions, feel free to drop us a line on our [Discord](https://discord.com/invite/VU53p7uQcE)

---

## File: client/packages/admin/README.md

[Get Started](https://www.instantdb.com/docs/backend) ·
   [Examples](https://instantdb.com/examples) ·
   [Docs](https://www.instantdb.com/docs/backend) ·
   [Discord](https://discord.com/invite/VU53p7uQcE)


Welcome to [Instant's](http://instantdb.com) admin SDK.

```javascript
import { init, tx, id } from '@instantdb/admin';

const adminDB = init({
  appId: 'my-instant-app-id',
  adminToken: process.env.INSTANT_APP_ADMIN_TOKEN,
});

const data = await adminDB.query(
  { bookshelves: { books: {} } }, // wohoo!
);
```

# Get Started

Head on over to the [Instant on the Backend](https://www.instantdb.com/docs/backend) page in the docs to get started!

# Questions?

If you have any questions, feel free to drop us a line on our [Discord](https://discord.com/invite/VU53p7uQcE)

---

## File: client/sandbox/vanilla-js-vite/README.md

This is sandbox app to play with [@instantdb/core](../../packages/core/).

# Development

First, let's set up your environment. Create an Instant app, either on your local backend or prod, and fill out the token info in your `.env` file.

```bash
cp .env.example .env
# fill in the variables in .env
```

Once done, load [localhost:5173](http://localhost:5173), and you'll see a basic example with auth.

# Questions?

If you have any questions, feel free to drop us a line on our [Discord](https://discord.com/invite/VU53p7uQcE)!

---

## File: client/sandbox/vanilla-js-nuxt/README.md

# InstantDB's id() Issue Repro

InstantDB's `id()` function does not work in server endpoints, even though `v4()` from `uuid`
does.

## Key Files of Interest

- [app.vue](/app.vue): Calls the test API endpoint and logs IDs generated client-side.
- [server/api/createId.ts](/server/api/createId.ts): Attempts to generate IDs using both `uuid` and `@instantdb/admin` on the server.

## The Issue

- **Client-side:** Both `id()` from `@instantdb/core` and `v4()` from `uuid` function as expected when they run client-side (ie: when called directly by the button in `app.vue`).
- **Server-side:**
  - `v4()` from `uuid` works correctly when called within the `/api/createId` endpoint (`server/api/createId.ts`). but `id()` from `@instantdb/admin` throws an error (at line 12).

The error thrown is: `dist$1.id is not a function`.

This is unexpected because `id()` in `@instantdb/admin` appears to be a direct re-export or wrapper around `v4()` from `uuid`.

## Reproduction Steps

Install dependencies:

```bash
# pnpm
pnpm install
```

Start the development server:

```bash
# pnpm
pnpm dev
```

Then, clicking the button on the page will trigger the API call and print the error on the scren. Inspecting the browser console or server console in your IDE will reveal more detailed logs.

---

## File: client/sandbox/strong-init-vite/README.md

This is sandbox app to play with strong-init.

# Development

First, let's set up your environment. Create an Instant app, either on your local backend or prod, and fill out the token info in your `.env` file.

```bash
cp .env.example .env
# fill in the variables in .env
```

Once done, load [localhost:5173](http://localhost:5173), and you'll see a basic example with auth.

# Questions?

If you have any questions, feel free to drop us a line on our [Discord](https://discord.com/invite/VU53p7uQcE)!