> ## Documentation Index
> Fetch the complete documentation index at: https://docs.bijection.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Bijection Tutorial: A chat app

> Build a real-time chat application with Bijection using queries, mutations, and the sync engine for automatic updates across all connected clients.

Bijection provides you with a fully featured backend with cloud functions,
database, scheduling, and a sync engine that keeps your frontend and backend up
to date in real-time.

Today, in about **10 lines of code,** we'll build a backend that reads and
writes to the database and automatically updates all users in a chat app.

After that we'll see how to connect to external services and setup your product
for success and scale.

<div className="center-image" style={{ maxWidth: "560px" }} />

## Start developing with Bijection

<Accordion title="Before you begin: You'll need the Bijection CLI and Node.js">
  Install the Bijection command line on macOS or Linux:

  ```shell theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  curl -fsSL https://bijection.com/install.sh | sh
  ```

  See [Install Bijection](/get-started/install) for PATH setup. The backend
  needs nothing else, but the chat app's web frontend is a React app built with
  Vite, so you also need [Node.js](https://nodejs.org/en) with a package
  manager: pnpm, bun, yarn or npm.
</Accordion>

First, create the app from the `react-vite` template:

```shell theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
bijection init chat --template react-vite
cd chat
```

`bijection init` writes a React app and a folder called `bijection/`, where
you'll write your backend code, and installs the app's dependencies with your
package manager.

Log this machine in to Bijection (once per machine), then start the backend:

```shell theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
bijection login
bijection dev
```

<Note>
  Bijection's hosted service is not yet open for public sign-up, and the CLI
  has no default management service. Before running `bijection login`, set
  `BIJECTION_MANAGEMENT_URL` to the management service URL you were given, in
  your shell's startup file so that every later `bijection` command sees it too:

  ```sh theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  export BIJECTION_MANAGEMENT_URL=https://<your management service>
  ```
</Note>

The first run of `bijection dev` **creates your backend**, a dev deployment, and
writes its URL to `.env.local`, where the app finds it.

**Make sure you keep `bijection dev` running in the background throughout this
tutorial.** It keeps your backend in sync with your local codebase, pushing the
`bijection/` folder on every change.

In another terminal, start the web app with the command `bijection init`
printed for your package manager, for example:

```shell theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
npm run dev
```

The template came with a sample message list, in `bijection/messages.ts` and
`bijection/schema.ts`. In this tutorial you write the chat backend yourself, so
delete them:

```shell theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
rm bijection/messages.ts bijection/schema.ts
```

The app at [localhost:5173](http://localhost:5173) still calls the functions
you deleted, so it shows an error until you connect it to your own functions
below. First, here's a quick summary of how Bijection works.

## How Bijection works

```mermaid theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
flowchart LR
    subgraph userA[Web app: user A]
        clientA[Client library]
    end
    subgraph userB[Web app: user B]
        clientB[Client library]
    end
    subgraph backend[Bijection backend]
        subgraph sync[Sync engine]
            mutation[Mutation] --> db[(Database)]
            db --> query[Query]
        end
    end
    clientA --> mutation
    query --> clientA
    query --> clientB
```

**Database.** The Bijection database is a document-relational database, which means
you have tables with JSON like documents in them. All documents have an
auto-generated `_id` that can be used to create relations between documents. You
interact with the database through mutation and query functions that are written
entirely in TypeScript.

**Mutation functions.** Mutations are TypeScript functions that update the
database. All mutation functions in Bijection run as a database transaction. So
either all the changes are committed, or none are.

**Query functions.** Queries are TypeScript functions that can only read from
the database. As we'll see in a bit, you subscribe to them from your frontend to
keep your app automatically up to date.

Your frontend registers to listen to query updates through the **client
library**. The client libraries talk to Bijection via WebSockets for fast realtime
updates.

The **sync engine** reruns query functions when any input to the function
changes, including any changes to the documents in the database that the query
reads. It then updates every app listening to the query. The sync engine is the
combination of queries, mutations and the database.

Now, let's dive into the code!

## Your first `mutation`

Create a new file in your `bijection/` folder called `chat.ts`. This is where
you'll write your Bijection backend functions for this application.

**Add the following to your `bijection/chat.ts` file.**

```typescript theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
import { mutation } from "./_generated/server";
import { v } from "bijection/values";

export const sendMessage = mutation({
  args: {
    user: v.string(),
    body: v.string(),
  },
  handler: async (ctx, args) => {
    console.log("This TypeScript function is running on the server.");
    await ctx.db.insert("messages", {
      user: args.user,
      body: args.body,
    });
  },
});
```

Let's break this down:

1. You've added a new backend `mutation` function called `sendMessage` and
   exposed it as a public api.
2. The whole function automatically runs as a transaction that will roll back if
   an exception is thrown.
3. Since this is just a TypeScript function you can drop `console.log` lines to
   do simple debugging on the server.
4. `args:` ensures the function arguments are two strings named `user` and
   `body`, both as types and runtime values.
5. `ctx.db.insert` tells Bijection to insert a new message document into the table.

Now, let's connect this mutation to your web app.

**Replace your `src/App.tsx` file with this chat UI:**

```tsx {1-2,12,17} theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
import { useMutation } from "bijection/react";
import { api } from "../bijection/_generated/api";
import { FormEvent, useState } from "react";

const NAME = "me";

type Message = { _id: string; user: string; body: string };

export default function App() {
  // There is no query yet, so the list stays empty.
  const messages: Message[] | undefined = [];
  const sendMessage = useMutation(api.chat.sendMessage);
  const [newMessageText, setNewMessageText] = useState("");

  async function submit(event: FormEvent) {
    event.preventDefault();
    await sendMessage({ user: NAME, body: newMessageText });
    setNewMessageText("");
  }

  return (
    <main>
      <h1>Chat</h1>
      {messages === undefined ? (
        <p>Loading…</p>
      ) : (
        <ul>
          {messages.map((message) => (
            <li key={message._id}>
              <strong>{message.user}</strong>: {message.body}
            </li>
          ))}
        </ul>
      )}
      <form onSubmit={submit}>
        <input
          value={newMessageText}
          onChange={(event) => setNewMessageText(event.target.value)}
          placeholder="Write a message…"
        />
        <button type="submit" disabled={newMessageText === ""}>
          Send
        </button>
      </form>
    </main>
  );
}
```

There are two steps to call a mutation in your frontend:

1. `const sendMessage = useMutation(api.chat.sendMessage);` gives your frontend
   app a handle to the mutation function
2. `await sendMessage({ user: NAME, body: newMessageText });` calls the mutation
   with the proper parameters.

This is a good time to **open up the Bijection console**. Open a new browser
window and go to [https://console.bijection.com](https://console.bijection.com)
and find your new project.

**Go to the "Data" screen**. So far, there is no data in your database.

**Keep your chat app and console windows open side by side**. Now try to send
some messages from your chat app.

You'll notice new chat messages showing up live in the `messages` table.

Bijection automatically created a `messages` table when you sent the first message.
In Bijection, [schemas](/database/schemas) are optional. Eventually, you'll
want to enforce the structure of your tables, but for the purposes of the
tutorial we'll skip this.

In the console you can also go to the
[logs screen](https://console.bijection.com) and see every call
to the mutation as you ran with the log line we added earlier. The logs screen
is a critical part of debugging your backend in development.

You've successfully created a `mutation` function, which is also a database
transaction, and connected it to your UI.

Now, let's make sure your app can update live the same way the console is
updating live.

## Your first `query`

**Update your `bijection/chat.ts` file like this:**

```tsx {1-2,6-15} theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
// Update your server import like this:
import { query, mutation } from "./_generated/server";

// ...

// Add the following function to the file:
export const getMessages = query({
  args: {},
  handler: async (ctx) => {
    // Get most recent messages first
    const messages = await ctx.db.query("messages").order("desc").take(50);
    // Reverse the list so that it's in a chronological order.
    return messages.reverse();
  },
});
```

Let's break this down:

1. You've added a new backend `query` function called `getMessages` and exposed
   it as a public api.
2. Since this is a query function, the `ctx.db` in this function only lets you
   read data.
3. In the first line of the `handler` you are querying the most recent 50
   messages from newest to oldest.
4. In the second line you're reversing the list using plain old TypeScript.

**Now update `src/App.tsx` to read from your query:**

```tsx {1-2,7-8} theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
// Update your bijection/react import like this:
import { useQuery, useMutation } from "bijection/react";

//...

export default function App() {
  // Replace the `const messages = ...` line with the following
  const messages = useQuery(api.chat.getMessages);

  //...
}
```

That one `useQuery` line is doing a lot of work automatically for you. It's
telling the Bijection client library to subscribe to your `getMessages` function.
Anytime there are new messages to show the query function is automatically
rerun. The result is put in `const messages` variable and React rerenders your
UI component to show the latest messages.

That's it. Now go back to your app and try sending messages.

Your app should be showing live updates as new messages arrive:

<br />

<br />

Don't believe it? Try opening two chat windows side by side and send some
messages:

## What you built

With just a few lines of code you've built a live updating chat app.

1. You created a `mutation` TypeScript function that, in a transaction, adds new
   chat messages to your database.
2. You created a `query` TypeScript function updates your app with the latest
   data.
3. You used the client library that keeps your frontend in live sync with the
   backend.

You've learned the fundamentals of Bijection and the sync engine that powers
everything.

## Next up

In this tutorial we just touched on the very basics. It's ok to just stop here
and go explore the rest of the docs, including
[efficient queries via indexes](/database/reading-data/indexes/indexes) and
traversing
[relationships through joins](/database/reading-data/reading-data#join). If
you're deeply curious about how Bijection works, you can read this
excellent deep dive.

But if you want to see how to call external services and build sophisticated
backend workflows, jump into the [next section →](/tutorial/actions).

<CardGroup cols={1}>
  <Card title="Calling external services" href="/tutorial/actions">
    Extend your chat app by calling external APIs using Bijection actions and the scheduler to integrate Wikipedia summaries into your application.
  </Card>
</CardGroup>
