Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 5 additions & 0 deletions .changeset/warm-panthers-thank.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@electric-sql/start': major
---

feat: publish the @electric-sql/start package
9 changes: 7 additions & 2 deletions examples/tanstack-db-web-starter/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@ DATABASE_URL=postgresql://postgres:password@localhost:54321/electric
# Generate a strong secret (minimum 32 characters)
BETTER_AUTH_SECRET=

# Production Electric Cloud Configuration (optional)
# Electric Cloud Configuration (optional)
# Get these from https://dashboard.electric-sql.cloud/
# or use `npx @electric-sql/start` to provision automatically.
# If not set, it will try to connect to local Electric at `http://localhost:30000`
# and you can start it using `pnpm backend:up`
#
# ELECTRIC_URL=https://api.electric-sql.cloud
# ELECTRIC_SOURCE_ID=your-source-id
# ELECTRIC_SOURCE_SECRET=your-source-secret
# ELECTRIC_SECRET=your-source-secret
4 changes: 4 additions & 0 deletions examples/tanstack-db-web-starter/.stackblitzrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"installDependencies": false,
"startCommand": "npx @electric-sql/start . && pnpm dev"
}
3 changes: 2 additions & 1 deletion examples/tanstack-db-web-starter/.tool-versions
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
nodejs 24.11.1
nodejs 24.11.1
caddy 2.10.2
25 changes: 19 additions & 6 deletions examples/tanstack-db-web-starter/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,26 @@ We sync normalized data from tables into TanStack DB collections in the client &

## General Usage

Read https://electric-sql.com/AGENTS.md for general information on developing wth Electric and TanStack DB.
You MUST read https://electric-sql.com/AGENTS.md for general information on developing wth Electric and TanStack DB.

## Starter template specifics

You CAN choose to read the `README.md` for this project if useful. Much of it is summarized below.

### Pre-reqs

Docker, Caddy (with root cert installed using `caddy trust`), Node and pnpm. Versions in `.tool-versions`.

### Initial setup

Before you started, all necessary package install is done via `pnpm install` and a dev server is started with `pnpm dev`.
```sh
pnpm install # install deps
pnpm backend:up # run backend services using docker compose
pnpm migrate # apply migrations
pnpm dev # run dev server
```

The dev server runs over HTTPS via a CaddyPlugin in the vite config. This supports HTTP/2 which is essential to avoid slow shapes for Electric.

### Linting and formatting

Expand All @@ -26,11 +39,11 @@ This command will also report linter errors that were not automatically fixable.

### Build/Test Commands

- `pnpm run dev` - Start development server with Docker services
- `pnpm run build` - Build for production
- `pnpm run test` - Run all Vitest tests
- `pnpm dev` - Start development server with Docker services
- `pnpm build` - Build for production
- `pnpm test` - Run all Vitest tests
- `vitest run <test-file>` - Run single test file
- `pnpm run start` - Start production server
- `pnpm start` - Start production server

### Architecture

Expand Down
99 changes: 59 additions & 40 deletions examples/tanstack-db-web-starter/README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,34 @@
Welcome to your new TanStack [Start](https://tanstack.com/start/latest) / [DB](https://tanstack.com/db/latest) + [Electric](https://electric-sql.com/) app!

# Getting Started
# Getting started

## Create a new project
## Pre-requisites

You need:

- [Docker](https://www.docker.com)
- [Caddy](https://caddyserver.com)
- [Node](https://nodejs.org/en) with [pnpm](https://pnpm.io)

You can see compatible versions in the `.tool-versions` file.

### Docker

Make sure you have [Docker](https://www.docker.com) running. Docker is used to run the [Postgres](https://www.postgresql.org) and [Electric](https://electric-sql.com) services defined in `docker-compose.yaml`.

To create a new project based on this starter, run the following commands:
### Caddy

Make sure you have [Caddy installed](https://caddyserver.com/docs/install) and have [installed its root certificate](https://caddyserver.com/docs/command-line#caddy-trust) using:

```sh
caddy trust # may require sudo
```

Electric [benefits significantly from `HTTP/2` multiplexing](https://electric-sql.com/docs/guides/troubleshooting#slow-shapes-mdash-why-are-my-shapes-slow-in-the-browser-in-local-development). `HTTP/2` requires `HTTPS`. Caddy is necessary for `HTTPS` to work in local development.

## Quickstart

Create a new project based on this starter:

```sh
npx gitpick electric-sql/electric/tree/main/examples/tanstack-db-web-starter my-tanstack-db-project
Expand All @@ -17,42 +41,45 @@ Copy the `.env.example` file to `.env`:
cp .env.example .env
```

_You can edit the values in the `.env` file, although the default values are fine for local development (with the `DATABASE_URL` defaulting to the development Postgres docker container and the `BETTER_AUTH_SECRET` not required)._
> [!Tip]
> You can edit the values in the `.env` file. The default values are configured for local development with Docker. You can run against a different Postgres and Electric, for example using the Electric Cloud, by changing the `DATABASE_URL` and `ELECTRIC_URL`.

## Quick Start
Install the dependencies:

Follow these steps in order for a smooth first-time setup:
```sh
pnpm install
```

1. **Install dependencies:**
Start the backend services (Postgres and Electric) running in the background using Docker:

```sh
pnpm install
```
```sh
pnpm backend:up
```

2. **Start Docker services:**
Apply the database migrations:

```sh
pnpm run dev
```
```sh
pnpm migrate
```

This starts the dev server, Docker Compose (Postgres + Electric), and Caddy automatically.
Start the dev server:

3. **Run database migrations** (in a new terminal):
```sh
pnpm dev
```

```sh
pnpm run migrate
```
Open the application on [https://localhost:5173](https://localhost:5173).

4. **Visit the application:**
Open [https://tanstack-start-db-electric-starter.localhost](https://tanstack-start-db-electric-starter.localhost)
> [!Tip]
> If you run into any issues, see the [troubleshooting](#troubleshooting) section below.

If you run into issues, see the [pre-reqs](#pre-requisites) and [troubleshooting](#common-pitfalls) sections below.
# Developing your app

## Adding a New Table

Here's how to add a new table to your app (using a "categories" table as an example):

### 1. Define the Drizzle Schema
### 1. Define the Drizzle schema

Add your table to `src/db/schema.ts`:

Expand All @@ -75,7 +102,7 @@ export const createCategorySchema = createInsertSchema(categoriesTable).omit({
export const updateCategorySchema = createUpdateSchema(categoriesTable)
```

### 2. Generate & Run Migration
### 2. Generate and run migrations

```sh
# Generate migration file
Expand All @@ -85,7 +112,7 @@ pnpm migrate:generate
pnpm migrate
```

### 3. Add Electric Shape Route
### 3. Expose an Electric shape route

Create `src/routes/api/categories.ts`:

Expand Down Expand Up @@ -117,7 +144,7 @@ export const ServerRoute = createServerFileRoute("/api/categories").methods({
})
```

### 4. Add tRPC Router
### 4. Add a tRPC router

Create `src/lib/trpc/categories.ts`:

Expand Down Expand Up @@ -150,7 +177,7 @@ export const categoriesRouter = router({
})
```

### 5. Wire Up tRPC Router
### 5. Wire up the tRPC router

Add to `src/routes/api/trpc/$.ts`:

Expand All @@ -163,7 +190,7 @@ export const appRouter = router({
})
```

### 6. Add Collection
### 6. Add a TanStack DB collection

Add to `src/lib/collections.ts`:

Expand Down Expand Up @@ -192,7 +219,7 @@ export const categoriesCollection = createCollection(
)
```

### 7. Use in Routes
### 7. Use the collection in your routes

Preload in route loaders and use with `useLiveQuery`:

Expand All @@ -212,17 +239,9 @@ const { data: categories } = useLiveQuery((q) =>

That's it! Your new table is now fully integrated with Electric sync, tRPC mutations, and TanStack DB queries.

## Pre-requisites

This project uses [Docker](https://www.docker.com), [Node](https://nodejs.org/en) with [pnpm](https://pnpm.io) and [Caddy](https://caddyserver.com/). You can see compatible versions in the `.tool-versions` file.

### Docker

Make sure you have Docker running. Docker is used to run the Postgres and Electric services defined in `docker-compose.yaml`.

### Caddy
## Notes

#### Why Caddy?
### About Caddy

Electric SQL's shape delivery benefits significantly from **HTTP/2 multiplexing**. Without HTTP/2, each shape subscription creates a new HTTP/1.1 connection, which browsers limit to 6 concurrent connections per domain. This creates a bottleneck that makes shapes appear slow.

Expand Down Expand Up @@ -315,7 +334,7 @@ caddy start
To build this application for production:

```bash
pnpm run build
pnpm build
```

### Production Deployment Checklist
Expand Down
2 changes: 1 addition & 1 deletion examples/tanstack-db-web-starter/drizzle.config.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import "dotenv/config"
import "@dotenvx/dotenvx/config"
import { defineConfig } from "drizzle-kit"

export default defineConfig({
Expand Down
9 changes: 7 additions & 2 deletions examples/tanstack-db-web-starter/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,15 @@
"node": ">=20.19.0 || >=22.12.0"
},
"scripts": {
"dev": "docker compose up -d && vite dev",
"dev": "vite dev",
"backend:up": "docker compose up -d",
"backend:down": "docker compose down",
"backend:clear": "docker compose down -v",
"start": "node .output/server/index.mjs",
"build": "vite build",
"migrate": "drizzle-kit migrate",
"migrate:generate": "drizzle-kit generate",
"psql": "dotenvx run -- sh -c 'psql \"$DATABASE_URL\"'",
"serve": "vite preview",
"test": "echo 'No tests yet'",
"lint:check": "eslint .",
Expand Down Expand Up @@ -43,6 +47,7 @@
"zod": "^4.0.14"
},
"devDependencies": {
"@dotenvx/dotenvx": "^1.51.2",
"@eslint/compat": "^1.3.1",
"@eslint/js": "^9.32.0",
"@tanstack/devtools-vite": "^0.3.11",
Expand All @@ -56,12 +61,12 @@
"@typescript-eslint/parser": "^8.46.0",
"@vitejs/plugin-react": "^5.0.4",
"drizzle-kit": "^0.31.4",
"dotenv": "^17.2.1",
"eslint": "^9.32.0",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-prettier": "^5.5.3",
"eslint-plugin-react": "^7.37.5",
"jsdom": "^27.0.0",
"open-cli": "^8.0.0",
"prettier": "^3.6.2",
"tsx": "^4.20.3",
"typescript": "^5.7.2",
Expand Down
10 changes: 8 additions & 2 deletions examples/tanstack-db-web-starter/src/db/connection.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import "dotenv/config"
import "@dotenvx/dotenvx/config"
import { drizzle } from "drizzle-orm/node-postgres"
import { Pool } from "pg"

export const db = drizzle(process.env.DATABASE_URL!, { casing: `snake_case` })
const databaseUrl = process.env.DATABASE_URL
if (!databaseUrl) {
throw new Error(`DATABASE_URL is not set`)
}
const pool = new Pool({ connectionString: databaseUrl })
export const db = drizzle({ client: pool, casing: `snake_case` })
21 changes: 15 additions & 6 deletions examples/tanstack-db-web-starter/src/lib/electric-proxy.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
import "@dotenvx/dotenvx/config"
import { ELECTRIC_PROTOCOL_QUERY_PARAMS } from "@electric-sql/client"

/**
* Gets the Electric SQL endpoint URL based on environment configuration.
*
* If running in production, or `USE_ELECTRIC_URL` is set to `true`, the `ELECTRIC_URL` env var is used,
* if available, otherwise the default cloud endpoint is used.
* Otherwise, the local docker endpoint is used, assuming default port 30000.
*/
function getElectricUrl(): string {
return process.env.ELECTRIC_URL || `http://localhost:30000`
}

/**
* Prepares the Electric SQL proxy URL from a request URL
* Copies over Electric-specific query params and adds auth if configured
Expand All @@ -8,10 +20,7 @@ import { ELECTRIC_PROTOCOL_QUERY_PARAMS } from "@electric-sql/client"
*/
export function prepareElectricUrl(requestUrl: string): URL {
const url = new URL(requestUrl)
const electricUrl =
process.env.NODE_ENV === `production`
? `https://api.electric-sql.cloud`
: `http://localhost:30000`
const electricUrl = getElectricUrl()
const originUrl = new URL(`${electricUrl}/v1/shape`)

// Copy Electric-specific query params
Expand All @@ -22,9 +31,9 @@ export function prepareElectricUrl(requestUrl: string): URL {
})

// Add Electric Cloud authentication if configured
if (process.env.ELECTRIC_SOURCE_ID && process.env.ELECTRIC_SOURCE_SECRET) {
if (process.env.ELECTRIC_SOURCE_ID && process.env.ELECTRIC_SECRET) {
originUrl.searchParams.set(`source_id`, process.env.ELECTRIC_SOURCE_ID)
originUrl.searchParams.set(`secret`, process.env.ELECTRIC_SOURCE_SECRET)
originUrl.searchParams.set(`secret`, process.env.ELECTRIC_SECRET)
}

return originUrl
Expand Down
Loading