Skip to content

Commit b211685

Browse files
committed
Add Node.js quickstart template and documentation
1 parent f7a2201 commit b211685

21 files changed

Lines changed: 835 additions & 0 deletions
Lines changed: 235 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
---
2+
title: Node.js Quickstart
3+
sidebar_label: Node.js
4+
slug: /quickstarts/nodejs
5+
hide_table_of_contents: true
6+
---
7+
8+
import { InstallCardLink } from "@site/src/components/InstallCardLink";
9+
import { StepByStep, Step, StepText, StepCode } from "@site/src/components/Steps";
10+
11+
12+
Get a SpacetimeDB Node.js app running in under 5 minutes.
13+
14+
## Prerequisites
15+
16+
- [Node.js](https://nodejs.org/) 18+ installed
17+
- [SpacetimeDB CLI](https://spacetimedb.com/install) installed
18+
19+
<InstallCardLink />
20+
21+
---
22+
23+
<StepByStep>
24+
<Step title="Create your project">
25+
<StepText>
26+
Run the `spacetime dev` command to create a new project with a SpacetimeDB module and Node.js client.
27+
28+
This will start the local SpacetimeDB server, publish your module, and generate TypeScript bindings.
29+
</StepText>
30+
<StepCode>
31+
```bash
32+
spacetime dev --template nodejs-ts
33+
```
34+
</StepCode>
35+
</Step>
36+
37+
<Step title="Explore the project structure">
38+
<StepText>
39+
Your project contains both server and client code.
40+
41+
Edit `spacetimedb/src/index.ts` to add tables and reducers. Edit `src/main.ts` to build your Node.js client.
42+
</StepText>
43+
<StepCode>
44+
```
45+
my-spacetime-app/
46+
├── spacetimedb/ # Your SpacetimeDB module
47+
│ └── src/
48+
│ └── index.ts # Server-side logic
49+
├── src/
50+
│ ├── main.ts # Node.js client script
51+
│ └── module_bindings/ # Auto-generated types
52+
└── package.json
53+
```
54+
</StepCode>
55+
</Step>
56+
57+
<Step title="Understand tables and reducers">
58+
<StepText>
59+
Open `spacetimedb/src/index.ts` to see the module code. The template includes a `person` table and two reducers: `add` to insert a person, and `say_hello` to greet everyone.
60+
61+
Tables store your data. Reducers are functions that modify data — they're the only way to write to the database.
62+
</StepText>
63+
<StepCode>
64+
```typescript
65+
import { schema, table, t } from 'spacetimedb/server';
66+
67+
export const spacetimedb = schema(
68+
table(
69+
{ name: 'person', public: true },
70+
{
71+
name: t.string(),
72+
}
73+
)
74+
);
75+
76+
spacetimedb.reducer('add', { name: t.string() }, (ctx, { name }) => {
77+
ctx.db.person.insert({ name });
78+
});
79+
80+
spacetimedb.reducer('say_hello', (ctx) => {
81+
for (const person of ctx.db.person.iter()) {
82+
console.info(`Hello, ${person.name}!`);
83+
}
84+
console.info('Hello, World!');
85+
});
86+
```
87+
</StepCode>
88+
</Step>
89+
90+
<Step title="Run the client">
91+
<StepText>
92+
In a new terminal, run the Node.js client. It will connect to SpacetimeDB and start an interactive CLI where you can add people and query the database.
93+
</StepText>
94+
<StepCode>
95+
```bash
96+
# Run with auto-reload during development
97+
npm run dev
98+
99+
# Or run once
100+
npm run start
101+
```
102+
</StepCode>
103+
</Step>
104+
105+
<Step title="Use the interactive CLI">
106+
<StepText>
107+
The client provides a command-line interface to interact with your SpacetimeDB module. Type a name to add a person, or use the built-in commands.
108+
</StepText>
109+
<StepCode>
110+
```
111+
Connecting to SpacetimeDB...
112+
URI: ws://localhost:3000
113+
Module: nodejs-ts
114+
115+
Connected to SpacetimeDB!
116+
Identity: abc123def456...
117+
118+
Current people (0):
119+
(none yet)
120+
121+
Commands:
122+
<name> - Add a person with that name
123+
list - Show all people
124+
hello - Greet everyone (check server logs)
125+
Ctrl+C - Quit
126+
127+
> Alice
128+
[Added] Alice
129+
130+
> Bob
131+
[Added] Bob
132+
133+
> list
134+
People in database:
135+
- Alice
136+
- Bob
137+
138+
> hello
139+
Called say_hello reducer (check server logs)
140+
```
141+
</StepCode>
142+
</Step>
143+
144+
<Step title="Understand the client code">
145+
<StepText>
146+
Open `src/main.ts` to see the Node.js client. It uses `DbConnection.builder()` to connect to SpacetimeDB, subscribes to tables, and sets up the interactive CLI using Node's `readline` module.
147+
148+
Unlike browser apps, Node.js stores the authentication token in a file instead of localStorage.
149+
</StepText>
150+
<StepCode>
151+
```typescript
152+
import { DbConnection } from './module_bindings/index.js';
153+
154+
// Build and establish connection
155+
const conn = DbConnection.builder()
156+
.withUri(HOST)
157+
.withModuleName(DB_NAME)
158+
.withToken(loadToken()) // Load saved token from file
159+
.onConnect((conn, identity, token) => {
160+
console.log('Connected! Identity:', identity.toHexString());
161+
saveToken(token); // Save token for future connections
162+
163+
// Subscribe to all tables
164+
conn.subscriptionBuilder()
165+
.onApplied((ctx) => {
166+
// Show current data, start CLI
167+
setupCLI();
168+
})
169+
.subscribeToAllTables();
170+
171+
// Listen for table changes
172+
conn.db.person.onInsert((ctx, person) => {
173+
console.log(`[Added] ${person.name}`);
174+
});
175+
})
176+
.build();
177+
```
178+
</StepCode>
179+
</Step>
180+
181+
<Step title="Test with the SpacetimeDB CLI">
182+
<StepText>
183+
You can also use the SpacetimeDB CLI to call reducers and query your data directly. Changes made via the CLI will appear in your Node.js client in real-time.
184+
</StepText>
185+
<StepCode>
186+
```bash
187+
# Call the add reducer to insert a person
188+
spacetime call <database-name> add Charlie
189+
190+
# Query the person table
191+
spacetime sql <database-name> "SELECT * FROM person"
192+
name
193+
---------
194+
"Alice"
195+
"Bob"
196+
"Charlie"
197+
198+
# Call say_hello to greet everyone
199+
spacetime call <database-name> say_hello
200+
201+
# View the module logs
202+
spacetime logs <database-name>
203+
2025-01-13T12:00:00.000000Z INFO: Hello, Alice!
204+
2025-01-13T12:00:00.000000Z INFO: Hello, Bob!
205+
2025-01-13T12:00:00.000000Z INFO: Hello, Charlie!
206+
2025-01-13T12:00:00.000000Z INFO: Hello, World!
207+
```
208+
</StepCode>
209+
</Step>
210+
211+
<Step title="Node.js considerations">
212+
<StepText>
213+
**WebSocket support:** Node.js 22+ has native WebSocket support. For Node.js 18-21, the SDK automatically uses the `undici` package (included in devDependencies).
214+
215+
**Environment variables:** Configure the connection using `SPACETIMEDB_HOST` and `SPACETIMEDB_DB_NAME` environment variables.
216+
217+
**Graceful shutdown:** The template includes signal handlers for `SIGINT` and `SIGTERM` to cleanly disconnect when stopping the process.
218+
</StepText>
219+
<StepCode>
220+
```bash
221+
# Configure via environment variables
222+
SPACETIMEDB_HOST=ws://localhost:3000 \
223+
SPACETIMEDB_DB_NAME=my-app \
224+
npm run start
225+
226+
# Or use a .env file with dotenv
227+
```
228+
</StepCode>
229+
</Step>
230+
</StepByStep>
231+
232+
## Next steps
233+
234+
- See the [Chat App Tutorial](/tutorials/chat-app) for a complete example
235+
- Read the [TypeScript SDK Reference](/sdks/typescript) for detailed API docs

templates/nodejs-ts/.template.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"description": "Node.js TypeScript client and server template",
3+
"client_lang": "typescript",
4+
"server_lang": "typescript"
5+
}

templates/nodejs-ts/LICENSE

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../../licenses/apache2.txt

templates/nodejs-ts/package.json

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"name": "@clockworklabs/nodejs-ts",
3+
"private": true,
4+
"version": "0.0.1",
5+
"type": "module",
6+
"scripts": {
7+
"dev": "tsx watch src/main.ts",
8+
"start": "tsx src/main.ts",
9+
"build": "tsc",
10+
"spacetime:generate": "spacetime generate --lang typescript --out-dir src/module_bindings --project-path spacetimedb"
11+
},
12+
"dependencies": {
13+
"spacetimedb": "workspace:*"
14+
},
15+
"devDependencies": {
16+
"@types/node": "^20.0.0",
17+
"tsx": "^4.19.0",
18+
"typescript": "~5.6.2",
19+
"undici": "^6.19.2"
20+
}
21+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"name": "spacetime-module",
3+
"version": "1.0.0",
4+
"description": "",
5+
"scripts": {
6+
"build": "spacetime build",
7+
"publish": "spacetime publish"
8+
},
9+
"keywords": [],
10+
"author": "",
11+
"license": "ISC",
12+
"dependencies": {
13+
"spacetimedb": "1.*"
14+
}
15+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { schema, table, t } from 'spacetimedb/server';
2+
3+
export const spacetimedb = schema(
4+
table(
5+
{ name: 'person', public: true },
6+
{
7+
name: t.string(),
8+
}
9+
)
10+
);
11+
12+
spacetimedb.init(_ctx => {
13+
// Called when the module is initially published
14+
});
15+
16+
spacetimedb.clientConnected(_ctx => {
17+
// Called every time a new client connects
18+
});
19+
20+
spacetimedb.clientDisconnected(_ctx => {
21+
// Called every time a client disconnects
22+
});
23+
24+
spacetimedb.reducer('add', { name: t.string() }, (ctx, { name }) => {
25+
ctx.db.person.insert({ name });
26+
});
27+
28+
spacetimedb.reducer('say_hello', ctx => {
29+
for (const person of ctx.db.person.iter()) {
30+
console.info(`Hello, ${person.name}!`);
31+
}
32+
console.info('Hello, World!');
33+
});
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
2+
/*
3+
* This tsconfig is used for TypeScript projects created with `spacetimedb init
4+
* --lang typescript`. You can modify it as needed for your project, although
5+
* some options are required by SpacetimeDB.
6+
*/
7+
{
8+
"compilerOptions": {
9+
"strict": true,
10+
"skipLibCheck": true,
11+
"moduleResolution": "bundler",
12+
"jsx": "react-jsx",
13+
14+
/* The following options are required by SpacetimeDB
15+
* and should not be modified
16+
*/
17+
"target": "ESNext",
18+
"lib": ["ES2021", "dom"],
19+
"module": "ESNext",
20+
"isolatedModules": true,
21+
"noEmit": true
22+
},
23+
"include": ["./**/*"]
24+
}

0 commit comments

Comments
 (0)