diff --git a/docs/docs/00100-intro/00200-quickstarts/00152-astro.md b/docs/docs/00100-intro/00200-quickstarts/00152-astro.md
new file mode 100644
index 00000000000..0cf2f0daf4b
--- /dev/null
+++ b/docs/docs/00100-intro/00200-quickstarts/00152-astro.md
@@ -0,0 +1,181 @@
+---
+title: Astro Quickstart
+sidebar_label: Astro
+slug: /quickstarts/astro
+hide_table_of_contents: true
+---
+
+import { InstallCardLink } from "@site/src/components/InstallCardLink";
+import { StepByStep, Step, StepText, StepCode } from "@site/src/components/Steps";
+
+
+Get a SpacetimeDB Astro app running in under 5 minutes.
+
+## Prerequisites
+
+- [Node.js](https://nodejs.org/) 18+ installed
+- [SpacetimeDB CLI](https://spacetimedb.com/install) installed
+
+
+
+---
+
+
+
+
+ Run the `spacetime dev` command to create a new project with a SpacetimeDB module and Astro client.
+
+ This will start the local SpacetimeDB server, publish your module, generate TypeScript bindings, and start the Astro development server.
+
+
+```bash
+spacetime dev --template astro-ts
+```
+
+
+
+
+
+ Navigate to [http://localhost:4321](http://localhost:4321) to see your app running.
+
+ The Astro app reads `SPACETIMEDB_*` variables on the server and `PUBLIC_SPACETIMEDB_*` variables in the client, so `.env.local` can configure both sides of the app.
+
+
+
+
+
+ Your project contains both server and client code using Astro SSR and a live React island for real-time updates.
+
+ Edit `spacetimedb/src/index.ts` to add tables and reducers. Edit `src/pages/index.astro` and `src/components/PersonList.tsx` to build your UI.
+
+
+```text
+my-astro-app/
+├── spacetimedb/ # Your SpacetimeDB module
+│ └── src/
+│ └── index.ts # SpacetimeDB module logic
+├── src/
+│ ├── components/
+│ │ ├── PersonList.tsx
+│ │ ├── SpacetimeApp.tsx
+│ │ └── DeferredPeopleSnapshot.astro
+│ ├── lib/
+│ │ └── spacetimedb-server.ts
+│ ├── module_bindings/ # Auto-generated types
+│ ├── layouts/
+│ │ └── Layout.astro
+│ ├── pages/
+│ │ └── index.astro
+│ └── styles/
+│ └── global.css
+└── package.json
+```
+
+
+
+
+
+ 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 `sayHello` to greet everyone.
+
+ Tables store your data. Reducers are functions that modify data and are the only way to write to the database.
+
+
+```typescript
+import { schema, table, t } from 'spacetimedb/server';
+
+const spacetimedb = schema({
+ person: table(
+ { public: true },
+ {
+ name: t.string(),
+ }
+ ),
+});
+export default spacetimedb;
+
+export const add = spacetimedb.reducer(
+ { name: t.string() },
+ (ctx, { name }) => {
+ ctx.db.person.insert({ name });
+ }
+);
+
+export const sayHello = spacetimedb.reducer(ctx => {
+ for (const person of ctx.db.person.iter()) {
+ console.info(`Hello, ${person.name}!`);
+ }
+ console.info('Hello, World!');
+});
+```
+
+
+
+
+
+ Open a new terminal and navigate to your project directory. Then use the SpacetimeDB CLI to call reducers and query your data directly.
+
+
+```bash
+cd my-spacetime-app
+
+# Call the add reducer to insert a person
+spacetime call add Alice
+
+# Query the person table
+spacetime sql "SELECT * FROM person"
+ name
+---------
+ "Alice"
+
+# Call sayHello to greet everyone
+spacetime call say_hello
+
+# View the module logs
+spacetime logs
+2025-01-13T12:00:00.000000Z INFO: Hello, Alice!
+2025-01-13T12:00:00.000000Z INFO: Hello, World!
+```
+
+
+
+
+
+ The SpacetimeDB SDK works both server-side and client-side. The template uses a hybrid approach:
+
+ - **Astro page** (`src/pages/index.astro`): Fetches initial data on the server for a fast first render
+ - **React island** (`src/components/SpacetimeApp.tsx`): Hydrates on the client and provides the SpacetimeDB connection
+ - **Live table UI** (`src/components/PersonList.tsx`): Uses `useTable()` and `useReducer()` for real-time updates
+
+
+```astro
+---
+import Layout from '../layouts/Layout.astro';
+import SpacetimeApp from '../components/SpacetimeApp';
+import { fetchPeople } from '../lib/spacetimedb-server';
+
+const initialPeople = await fetchPeople();
+---
+
+
+
astro-ts
+
+
+```
+
+
+
+
+
+ The template also includes a deferred Astro-only section to demonstrate `server:defer`.
+
+ `src/components/DeferredPeopleSnapshot.astro` fetches its own server-rendered snapshot, and `src/pages/index.astro` renders it as a server island without changing the main real-time client flow.
+
+
+```astro
+
+
Loading deferred people snapshot…
+
+```
+
+
+
diff --git a/templates/astro-ts/.gitignore b/templates/astro-ts/.gitignore
new file mode 100644
index 00000000000..9e7cfe93106
--- /dev/null
+++ b/templates/astro-ts/.gitignore
@@ -0,0 +1,28 @@
+# build output
+dist/
+spacetimedb/dist/
+
+# generated types
+.astro/
+
+# dependencies
+node_modules/
+
+# logs
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+
+# environment variables
+.env
+.env.local
+.env.*.local
+.env.production
+
+# macOS-specific files
+.DS_Store
+
+# jetbrains setting folder
+.idea/
+
diff --git a/templates/astro-ts/.template.json b/templates/astro-ts/.template.json
new file mode 100644
index 00000000000..795b0c40260
--- /dev/null
+++ b/templates/astro-ts/.template.json
@@ -0,0 +1,13 @@
+{
+ "description": "Astro app with a TypeScript server module",
+ "client_framework": "Astro",
+ "client_lang": "typescript",
+ "server_lang": "typescript",
+ "builtWith": [
+ "astro",
+ "react",
+ "react-dom",
+ "typescript",
+ "spacetimedb"
+ ]
+}
diff --git a/templates/astro-ts/LICENSE b/templates/astro-ts/LICENSE
new file mode 100644
index 00000000000..18d511e85da
--- /dev/null
+++ b/templates/astro-ts/LICENSE
@@ -0,0 +1 @@
+../../licenses/apache2.txt
diff --git a/templates/astro-ts/README.md b/templates/astro-ts/README.md
new file mode 100644
index 00000000000..cc728b753a8
--- /dev/null
+++ b/templates/astro-ts/README.md
@@ -0,0 +1,137 @@
+Get a SpacetimeDB Astro app running in under 5 minutes.
+
+## Prerequisites
+
+- [Node.js](https://nodejs.org/) 18+ installed
+- [SpacetimeDB CLI](https://spacetimedb.com/install) installed
+
+Install the [SpacetimeDB CLI](https://spacetimedb.com/install) before continuing.
+
+---
+
+## Create your project
+
+Run the `spacetime dev` command to create a new project with a SpacetimeDB module and Astro client.
+
+This will start the local SpacetimeDB server, publish your module, generate TypeScript bindings, and start the Astro development server.
+
+```bash
+spacetime dev --template astro-ts
+```
+
+## Open your app
+
+Navigate to [http://localhost:4321](http://localhost:4321) to see your app running.
+
+The Astro app reads `SPACETIMEDB_*` variables on the server and `PUBLIC_SPACETIMEDB_*` variables in the client, so `.env.local` can configure both sides of the app.
+
+## Explore the project structure
+
+Your project contains both server and client code using Astro SSR and a live interactive client for real-time updates.
+
+Edit `spacetimedb/src/index.ts` to add tables and reducers. Edit `src/pages/index.astro` and `src/components/PersonList.tsx` to build your UI.
+
+```text
+my-astro-app/
+├── spacetimedb/ # Your SpacetimeDB module
+│ └── src/
+│ └── index.ts # SpacetimeDB module logic
+├── src/
+│ ├── components/
+│ │ ├── PersonList.tsx
+│ │ ├── SpacetimeApp.tsx
+│ │ └── DeferredPeopleSnapshot.astro
+│ ├── lib/
+│ │ └── spacetimedb-server.ts
+│ ├── module_bindings/ # Auto-generated types
+│ ├── layouts/
+│ │ └── Layout.astro
+│ ├── pages/
+│ │ └── index.astro
+│ └── styles/
+│ └── global.css
+└── package.json
+```
+
+## Understand tables and reducers
+
+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 `sayHello` to greet everyone.
+
+Tables store your data. Reducers are functions that modify data and are the only way to write to the database.
+
+```typescript
+import { schema, table, t } from 'spacetimedb/server';
+
+const spacetimedb = schema({
+ person: table(
+ { public: true },
+ {
+ name: t.string(),
+ }
+ ),
+});
+export default spacetimedb;
+
+export const add = spacetimedb.reducer(
+ { name: t.string() },
+ (ctx, { name }) => {
+ ctx.db.person.insert({ name });
+ }
+);
+
+export const sayHello = spacetimedb.reducer(ctx => {
+ for (const person of ctx.db.person.iter()) {
+ console.info(`Hello, ${person.name}!`);
+ }
+ console.info('Hello, World!');
+});
+```
+
+## Understand Astro SSR plus real-time hydration
+
+The template uses a hybrid rendering model:
+
+- `src/pages/index.astro` fetches the initial list of people on the server for a fast first paint.
+- `src/components/SpacetimeApp.tsx` hydrates with `client:load` and provides the SpacetimeDB connection.
+- `src/components/PersonList.tsx` subscribes to the `person` table with `useTable()` and calls reducers with `useReducer()`.
+
+This gives you server-rendered HTML on the first request and a live WebSocket-backed UI after hydration.
+
+## Understand Astro server islands
+
+The template also includes a deferred Astro-only section to demonstrate `server:defer`.
+
+- `src/components/DeferredPeopleSnapshot.astro` fetches its own server-rendered snapshot.
+- `src/pages/index.astro` renders it with `server:defer`, so it loads after the main page shell.
+
+This demonstrates an Astro-specific pattern without affecting the main real-time client flow.
+
+## Test with the CLI
+
+Open a new terminal and navigate to your project directory. Then use the SpacetimeDB CLI to call reducers and query your data directly.
+
+```bash
+cd my-spacetime-app
+
+# Call the add reducer to insert a person
+spacetime call add Alice
+
+# Query the person table
+spacetime sql "SELECT * FROM person"
+ name
+---------
+ "Alice"
+
+# Call sayHello to greet everyone
+spacetime call say_hello
+
+# View the module logs
+spacetime logs
+2025-01-13T12:00:00.000000Z INFO: Hello, Alice!
+2025-01-13T12:00:00.000000Z INFO: Hello, World!
+```
+
+## Next steps
+
+- See the [Chat App Tutorial](https://spacetimedb.com/docs/intro/tutorials/chat-app) for a complete example
+- Read the [TypeScript SDK Reference](https://spacetimedb.com/docs/intro/core-concepts/clients/typescript-reference) for detailed API docs
diff --git a/templates/astro-ts/astro.config.mjs b/templates/astro-ts/astro.config.mjs
new file mode 100644
index 00000000000..d1243fa519d
--- /dev/null
+++ b/templates/astro-ts/astro.config.mjs
@@ -0,0 +1,12 @@
+// @ts-check
+import node from '@astrojs/node';
+import react from '@astrojs/react';
+import { defineConfig } from 'astro/config';
+
+export default defineConfig({
+ output: 'server',
+ adapter: node({
+ mode: 'standalone',
+ }),
+ integrations: [react()],
+});
diff --git a/templates/astro-ts/package.json b/templates/astro-ts/package.json
new file mode 100644
index 00000000000..1e194115bb8
--- /dev/null
+++ b/templates/astro-ts/package.json
@@ -0,0 +1,30 @@
+{
+ "name": "@clockworklabs/astro-ts",
+ "private": true,
+ "version": "0.0.1",
+ "type": "module",
+ "scripts": {
+ "dev": "astro dev",
+ "build": "astro build",
+ "preview": "astro preview",
+ "start": "node ./dist/server/entry.mjs",
+ "astro": "astro",
+ "generate": "pnpm --dir spacetimedb install && cargo run -p gen-bindings -- --out-dir src/module_bindings --module-path spacetimedb && prettier --write src/module_bindings",
+ "spacetime:generate": "spacetime generate --lang typescript --out-dir src/module_bindings --module-path spacetimedb",
+ "spacetime:publish:local": "spacetime publish --module-path spacetimedb --server local",
+ "spacetime:publish": "spacetime publish --module-path spacetimedb --server maincloud"
+ },
+ "dependencies": {
+ "@astrojs/node": "^10.0.3",
+ "@astrojs/react": "^5.0.1",
+ "astro": "^6.0.8",
+ "react": "^18.3.1",
+ "react-dom": "^18.3.1",
+ "spacetimedb": "workspace:*"
+ },
+ "devDependencies": {
+ "@types/react": "^18.3.18",
+ "@types/react-dom": "^18.3.5",
+ "typescript": "~5.6.2"
+ }
+}
diff --git a/templates/astro-ts/public/favicon.svg b/templates/astro-ts/public/favicon.svg
new file mode 100644
index 00000000000..f157bd1c5e2
--- /dev/null
+++ b/templates/astro-ts/public/favicon.svg
@@ -0,0 +1,9 @@
+
diff --git a/templates/astro-ts/spacetimedb/package.json b/templates/astro-ts/spacetimedb/package.json
new file mode 100644
index 00000000000..8a263dc97a6
--- /dev/null
+++ b/templates/astro-ts/spacetimedb/package.json
@@ -0,0 +1,18 @@
+{
+ "name": "spacetime-module",
+ "version": "1.0.0",
+ "description": "",
+ "scripts": {
+ "build": "spacetime build",
+ "publish": "spacetime publish"
+ },
+ "keywords": [],
+ "author": "",
+ "license": "ISC",
+ "dependencies": {
+ "spacetimedb": "workspace:*"
+ },
+ "devDependencies": {
+ "typescript": "~5.6.2"
+ }
+}
diff --git a/templates/astro-ts/spacetimedb/src/index.ts b/templates/astro-ts/spacetimedb/src/index.ts
new file mode 100644
index 00000000000..3f4738743b1
--- /dev/null
+++ b/templates/astro-ts/spacetimedb/src/index.ts
@@ -0,0 +1,38 @@
+import { schema, table, t } from 'spacetimedb/server';
+
+const spacetimedb = schema({
+ person: table(
+ { public: true },
+ {
+ name: t.string(),
+ }
+ ),
+});
+export default spacetimedb;
+
+export const init = spacetimedb.init(_ctx => {
+ // Called when the module is initially published.
+});
+
+export const onConnect = spacetimedb.clientConnected(_ctx => {
+ // Called every time a new client connects.
+});
+
+export const onDisconnect = spacetimedb.clientDisconnected(_ctx => {
+ // Called every time a client disconnects.
+});
+
+export const add = spacetimedb.reducer(
+ { name: t.string() },
+ (ctx, { name }) => {
+ ctx.db.person.insert({ name });
+ }
+);
+
+export const sayHello = spacetimedb.reducer(ctx => {
+ for (const person of ctx.db.person.iter()) {
+ console.info(`Hello, ${person.name}!`);
+ }
+
+ console.info('Hello, World!');
+});
diff --git a/templates/astro-ts/spacetimedb/tsconfig.json b/templates/astro-ts/spacetimedb/tsconfig.json
new file mode 100644
index 00000000000..0bede6a959b
--- /dev/null
+++ b/templates/astro-ts/spacetimedb/tsconfig.json
@@ -0,0 +1,12 @@
+{
+ "compilerOptions": {
+ "target": "ES2020",
+ "module": "ESNext",
+ "moduleResolution": "bundler",
+ "strict": true,
+ "esModuleInterop": true,
+ "skipLibCheck": true,
+ "outDir": "./dist"
+ },
+ "include": ["src/**/*"]
+}
diff --git a/templates/astro-ts/src/components/DeferredPeopleSnapshot.astro b/templates/astro-ts/src/components/DeferredPeopleSnapshot.astro
new file mode 100644
index 00000000000..d58aed195f7
--- /dev/null
+++ b/templates/astro-ts/src/components/DeferredPeopleSnapshot.astro
@@ -0,0 +1,31 @@
+---
+import { fetchPeople } from '../lib/spacetimedb-server';
+
+const people = await fetchPeople();
+const renderedAt = new Intl.DateTimeFormat('en', {
+ hour: '2-digit',
+ minute: '2-digit',
+ second: '2-digit',
+}).format(new Date());
+---
+
+
+
Server-rendered snapshot
+
Rendered at {renderedAt}
+
+ This section is a plain Astro component rendered with server:defer. It fetches a
+ new SpacetimeDB snapshot on its own request, separately from the live client section above.
+
+
+ {people.length === 0 ? (
+
No people are in the table yet for this deferred snapshot.