Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
c65c6e2
First pass at reorganizing the docs and making them nice
cloutiertyler Oct 27, 2025
5a45fbb
macOS case insensitive garbage
cloutiertyler Oct 27, 2025
3c63267
Normalize docs folder casing (macOS-safe two-step renames)
cloutiertyler Oct 27, 2025
df3507a
casing, idk
cloutiertyler Oct 27, 2025
126f110
Trigger GitHub refresh after folder casing normalization
cloutiertyler Oct 27, 2025
d4e7d1d
Renumbering some entries
cloutiertyler Oct 27, 2025
b777be7
Updated the links (we cannot do redirections)
cloutiertyler Oct 29, 2025
38ad224
Normalize filenames to lowercase
cloutiertyler Oct 29, 2025
6915f2e
Might work
cloutiertyler Oct 29, 2025
7f28a48
Merge remote-tracking branch 'origin/master' into tyler/docs-reorg
cloutiertyler Oct 29, 2025
80298a9
stupid typo
cloutiertyler Oct 29, 2025
94f9e4b
Merged in master and took recent changes from the quickstart files
cloutiertyler Oct 31, 2025
2ed4e76
Merged master
cloutiertyler Oct 31, 2025
1c57f4a
[tyler/docs-reorg]: Merge remote-tracking branch 'origin/master' into…
bfops Nov 4, 2025
5b376e1
Merge branch 'master' into tyler/docs-reorg
cloutiertyler Nov 9, 2025
26f3d42
Merge origin/master
cloutiertyler Nov 20, 2025
f300732
Attempt to fix the quickstart
cloutiertyler Nov 24, 2025
2e67659
Merge branch 'master' into tyler/docs-reorg
cloutiertyler Nov 24, 2025
93a8e76
Merge branch 'master' into tyler/docs-reorg
cloutiertyler Nov 25, 2025
2f5294f
Update pnpm-lock.yaml
cloutiertyler Nov 26, 2025
daae87a
Merge branch 'master' into tyler/docs-reorg
cloutiertyler Nov 26, 2025
c8a8cec
fixed missing server annotations
cloutiertyler Nov 26, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,20 +1,30 @@
---
title: Overview
id: overview
slug: /
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import { InstallCardLink } from "@site/src/components/InstallCardLink";
import { CardLink } from "@site/src/components/CardLink";
import { CardLinkGrid } from "@site/src/components/CardLinkGrid";
import { QuickstartLinks } from "@site/src/components/QuickstartLinks";
import DocsList from "@site/src/components/DocsList";

# SpacetimeDB Documentation

## Installation

You can run SpacetimeDB as a standalone database server via the `spacetime` CLI tool.
You can get started by first installing the `spacetime` CLI tool. The `spacetime` CLI tool makes it extremely easy to manage your databases and deployments.

You can find the instructions to install the CLI tool for your platform [here](https://spacetimedb.com/install).
<InstallCardLink />

To get started running your own standalone instance of SpacetimeDB check out our [Getting Started Guide](/getting-started).
## Quickstart Guides

Choose your favorite language and follow one of our quickstart guides to get started building your first app with SpacetimeDB.

<QuickstartLinks />

## What is SpacetimeDB?

Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,272 @@
---
title: TypeScript Quickstart
slug: /sdks/typescript/quickstart
title: TypeScript
slug: /quickstarts/typescript
id: typescript
---

# TypeScript Client SDK Quickstart
import { InstallCardLink } from "@site/src/components/InstallCardLink";

In this guide, you'll learn how to use TypeScript to create a SpacetimeDB client application.
# Quickstart Chat App

Please note that TypeScript is supported as a client language only. **Before you get started on this guide**, you should complete one of the quickstart guides for creating a SpacetimeDB server module listed below.
In this tutorial, we'll implement a simple chat server as a SpacetimeDB **TypeScript** module.

- [Rust](/modules/rust/quickstart)
- [C#](/modules/c-sharp/quickstart)
A SpacetimeDB module is code that gets bundled to a single JavaScript artifact and uploaded to SpacetimeDB. This code becomes server-side logic that interfaces directly with SpacetimeDB’s relational database.

By the end of this introduction, you will have created a basic single page web app which connects to the `quickstart-chat` database created in the above module quickstart guides.
Each SpacetimeDB module defines a set of **tables** and a set of **reducers**.

- Tables are declared with `table({ ...opts }, { ...columns })`. Each inserted object is a row; each field is a column.
- Tables are **private** by default (readable only by the owner and your module code). Set `{ public: true }` to make them readable by everyone; writes still happen only via reducers.
- A **reducer** is a function that reads/writes the database. Each reducer runs in its own transaction; its writes commit only if it completes without throwing. In TypeScript, reducers are registered with `spacetimedb.reducer(name, argTypes, handler)` and throw `new SenderError("...")` for user-visible errors.

:::note
SpacetimeDB runs your module inside the database host (not Node.js). There’s no direct filesystem or network access from reducers.
:::

## Install SpacetimeDB

If you haven’t already, start by [installing SpacetimeDB](https://spacetimedb.com/install). This installs the `spacetime` CLI used to build, publish, and interact with your database.

<InstallCardLink />

## Project structure

Create and enter a directory `quickstart-chat`:

```bash
mkdir quickstart-chat
cd quickstart-chat
```

Initialize a **TypeScript** module project:

```bash
spacetime init --lang typescript server
```

This creates a `server/` project with a `src/index.ts` entrypoint (required for publishing).

## How to Build & Publish

:::info
TypeScript modules are built and published with the `spacetime` CLI. `spacetime publish` will transpile and bundle your server module for you starting with the `src/index.ts` entrypoint. If you bundle your js yourself, you can specify `spacetime publish --js-path <path-to-your-bundle-file>` when publishing.
:::

From the `server/` directory you can lint/typecheck locally if you like, but to make the module live you’ll publish it to a database:

```bash
cd server
spacetime publish --project-path server quickstart-chat
```

Publishing bundles your TypeScript into a single artifact and installs it into the `quickstart-chat` database.

## Declare imports

Open `server/src/index.ts`. Replace its contents with the following imports to start building a bare-bones real-time chat server:

```ts
import { schema, t, table, SenderError } from 'spacetimedb/server';
```

From `spacetimedb/server`, we import:

- `table` to define SpacetimeDB tables.
- `t` for column/type builders.
- `schema` to compose our database schema and register reducers.
- `SenderError` to signal user-visible (transaction-aborting) errors.

## Define tables

We’ll store two kinds of data: information about each user, and the messages that have been sent.

For each `User`, we’ll store their `identity` (the caller’s unique identifier), an optional display `name`, and whether they’re currently `online`. We’ll use `identity` as the primary key (unique and indexed).

Add to `server/src/index.ts`:

```ts
const User = table(
{ name: 'user', public: true },
{
identity: t.identity().primaryKey(),
name: t.string().optional(),
online: t.bool(),
}
);

const Message = table(
{ name: 'message', public: true },
{
sender: t.identity(),
sent: t.timestamp(),
text: t.string(),
}
);

// Compose the schema (gives us ctx.db.user and ctx.db.message, etc.)
const spacetimedb = schema(User, Message);
```

## Set users’ names

We’ll allow users to set a display name, since raw identities aren’t user-friendly. Define a reducer `set_name` that validates input, looks up the caller’s `User` row by primary key, and updates it. If there’s no user row (e.g., the caller invoked via CLI without a connection and hasn’t connected before), we’ll return an error.

Add:

```ts
function validateName(name: string) {
if (!name) {
throw new SenderError('Names must not be empty');
}
}

spacetimedb.reducer('set_name', { name: t.string() }, (ctx, { name }) => {
validateName(name);
const user = ctx.db.user.identity.find(ctx.sender);
if (!user) {
throw new SenderError('Cannot set name for unknown user');
}
ctx.db.user.identity.update({ ...user, name });
});
```

You can extend `validateName` with moderation checks, Unicode normalization, printable-character filtering, max length checks, or duplicate-name rejection.

## Send messages

Define a reducer `send_message` to insert a new `Message` with the caller’s identity and the call timestamp. As with names, we’ll validate that text isn’t empty.

Add:

```ts
function validateMessage(text: string) {
if (!text) {
throw new SenderError('Messages must not be empty');
}
}

spacetimedb.reducer('send_message', { text: t.string() }, (ctx, { text }) => {
validateMessage(text);
console.info(`User ${ctx.sender}: ${text}`);
ctx.db.message.insert({
sender: ctx.sender,
text,
sent: ctx.timestamp,
});
});
```

Possible extensions:

- Reject messages from users who haven’t set a name.
- Rate-limit messages per user.

## Set users’ online status

SpacetimeDB can invoke lifecycle reducers when clients connect/disconnect. We’ll create or update a `User` row to mark the caller online on connect, and mark them offline on disconnect.

Add:

```ts
// Called once when the module bundle is installed / updated.
// We'll keep it empty for this quickstart.
spacetimedb.init(_ctx => {});

spacetimedb.clientConnected(ctx => {
const user = ctx.db.user.identity.find(ctx.sender);
if (user) {
// Returning user: set online=true, keep identity/name.
ctx.db.user.identity.update({ ...user, online: true });
} else {
// New user: create a User row with no name yet.
ctx.db.user.insert({
identity: ctx.sender,
name: undefined,
online: true,
});
}
});

spacetimedb.clientDisconnected(ctx => {
const user = ctx.db.user.identity.find(ctx.sender);
if (user) {
ctx.db.user.identity.update({ ...user, online: false });
} else {
// Shouldn't happen (disconnect without prior connect)
console.warn(
`Disconnect event for unknown user with identity ${ctx.sender}`
);
}
});
```

## Start the server

If you haven’t already started the SpacetimeDB host on your machine, run this in a **separate terminal** and leave it running:

```bash
spacetime start
```

(If it’s already running, you can skip this step.)

## Publish the module

From the `quickstart-chat` directory (the parent of `server/`):

```bash
spacetime publish --project-path server quickstart-chat
```

You can choose any unique, URL-safe database name in place of `quickstart-chat`. The CLI will show the database **Identity** (a hex string) as well; you can use either the name or identity with CLI commands.

## Call reducers

Use the CLI to call reducers. Arguments are passed as JSON (strings may be given bare for single string parameters).

Send a message:

```bash
spacetime call quickstart-chat send_message "Hello, World!"
```

Check that it ran by viewing logs (owner-only):

```bash
spacetime logs quickstart-chat
```

You should see output similar to:

```text
<timestamp> INFO: spacetimedb: Creating table `message`
<timestamp> INFO: spacetimedb: Creating table `user`
<timestamp> INFO: spacetimedb: Database initialized
<timestamp> INFO: console: User 0x...: Hello, World!
```

## SQL queries

SpacetimeDB supports a subset of SQL so you can query your data:

```bash
spacetime sql quickstart-chat "SELECT * FROM message"
```

Output will resemble:

```text
sender | sent | text
--------------------------------------------------------------------+----------------------------------+-----------------
0x93dda09db9a56d8fa6c024d843e805d8262191db3b4ba84c5efcd1ad451fed4e | 2025-04-08T15:47:46.935402+00:00 | "Hello, World!"
```

You've just set up your first TypeScript module in SpacetimeDB! You can find the full code for this client [TypeScript server module example](https://github.com/clockworklabs/SpacetimeDB/tree/master/modules/quickstart-chat-ts).

# Creating the client

Next, you'll learn how to use TypeScript to create a SpacetimeDB client application.

By the end of this introduction, you will have created a basic single page web app which connects to the `quickstart-chat` database you just created.

## Project structure

Expand Down
Loading
Loading