# Pb React Spa

> React SPA frontend setup skill (PocketBase integration). Vite + TanStack Router (file-based routing) + TanStack Query + Tailwind CSS / Shadcn UI + Biome. Use when creating a React frontend, SPA setup, PocketBase UI, frontend project initialization, React app, or dashboard build.

- Skill: `ikumasudo/pb-react-spa` (Agent Skill, multi-file: 6 files)
- Install (CLI): `npx skillmds@latest add ikumasudo/pb-react-spa`
- Raw SKILL.md: https://api.skillmd.com/api/skills/ikumasudo/pb-react-spa/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Web & Frontend
- License: MIT
- Author: ikumasudo (https://skillmd.com/u/ikumasudo)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/ikumasudo/pb-react-spa

---


# PocketBase React SPA Skill

A skill that automates the setup of a React SPA frontend integrated with a PocketBase backend.

**Tech Stack:**
- **Vite** — Build tool / dev server
- **React + TypeScript** — UI framework
- **TanStack Router** — File-based routing
- **TanStack Query** — Server state management
- **Tailwind CSS + Shadcn UI** — Styling / UI components
- **Biome** — Linter / Formatter
- **PocketBase JS SDK** — Backend communication
- **pocketbase-typegen** — Type generation

## Skill Resources

- **References**: `references/` — Integration patterns, authentication, type generation, development & deployment guides
- **PocketBase backend skill**: The `pocketbase` skill handles backend management (collection CRUD, API rule design, etc.)

For details on the PocketBase JS SDK, also see `references/js-sdk.md` in the PocketBase skill.

## 0. Prerequisites

- **Node.js** v18 or higher, npm
- **PocketBase** is running (see the Bootstrap section in the `pocketbase` skill)
- PocketBase collection design is complete (recommended)

## 1. Project Scaffolding

### 1-1. Project Structure

Adopt a monorepo structure with separated frontend and backend:

```
project-root/
├── frontend/     ← React SPA (created by this skill)
├── backend/      ← PocketBase (managed by the pocketbase skill)
│   ├── pocketbase
│   ├── pb_data/
│   ├── pb_migrations/
│   └── .env
└── README.md
```

> **Note:** Check the user's existing project structure and adapt accordingly. The `frontend/` directory name can be changed based on user preference.

### 1-2. Base Project Generation

```bash
npx create-tsrouter-app@latest frontend \
  --toolchain biome \
  --package-manager npm \
  --no-git
```

> **Note:** `create-tsrouter-app` is a TanStack CLI wrapper where `--router-only` (file-based routing) is enabled by default. Tailwind CSS v4 is also set up automatically.

This command sets up the following:
- Vite + React + TypeScript
- TanStack Router (file-based routing)
- Tailwind CSS v4
- Biome (Linter / Formatter)

### 1-3. Adding Shadcn UI

```bash
cd frontend && npx shadcn@latest init -d
```

The `-d` flag uses default settings (new-york style, neutral color). A `components.json` file is created, enabling you to add components to `@/components/ui/`.

Example of adding components:

```bash
npx shadcn@latest add button card input label
```

### 1-4. Adding TanStack Query

```bash
npm install @tanstack/react-query
```

### 1-5. Installing PocketBase JS SDK

```bash
npm install pocketbase
```

### 1-6. Installing pocketbase-typegen

```bash
npm install -D pocketbase-typegen
```

### 1-7. Verifying the Setup

```bash
npm run build
```

Verify that the build completes successfully. To check the dev server, run `npm run dev`.

## 2. Post-Setup Configuration

After scaffolding, add the following configurations in order.

### 2-1. PocketBase Client

Create **`frontend/src/lib/pocketbase.ts`**:

```ts
import PocketBase from "pocketbase";
import type { TypedPocketBase } from "../types/pocketbase-types";

export const pb = new PocketBase() as TypedPocketBase;

pb.autoCancellation(false);
```

> **TypedPocketBase** is the type generated by `pocketbase-typegen`. If types haven't been generated yet, temporarily use the `PocketBase` type directly and replace it after generation:
>
> ```ts
> // Temporary version before type generation
> import PocketBase from "pocketbase";
> export const pb = new PocketBase();
> pb.autoCancellation(false);
> ```

### 2-2. Vite Proxy Configuration

Edit **`frontend/vite.config.ts`** to add `server.proxy`.

The generated `vite.config.ts` has the following structure:

```ts
import { defineConfig } from "vite";
import { devtools } from "@tanstack/devtools-vite";
import tsconfigPaths from "vite-tsconfig-paths";
import { tanstackRouter } from "@tanstack/router-plugin/vite";
import viteReact from "@vitejs/plugin-react";
import tailwindcss from "@tailwindcss/vite";

const config = defineConfig({
  plugins: [
    devtools(),
    tsconfigPaths({ projects: ["./tsconfig.json"] }),
    tailwindcss(),
    tanstackRouter({ target: "react", autoCodeSplitting: true }),
    viteReact(),
  ],
  // ↓ Add this
  server: {
    proxy: {
      "/api": {
        target: "http://127.0.0.1:8090",
        changeOrigin: true,
      },
      "/_": {
        target: "http://127.0.0.1:8090",
        changeOrigin: true,
      },
    },
  },
});

export default config;
```

> `/api` is the PocketBase REST API, and `/_` is for PocketBase internal endpoints (realtime SSE, etc.).
>
> **Why no URL in the PocketBase client?** The proxy makes all PocketBase API requests same-origin during development (browser sees `localhost:5173/api/...`). In production, PocketBase serves the SPA from `pb_public/`, which is also same-origin. Since both environments are same-origin, `new PocketBase()` (no arguments) works everywhere — no environment variables needed.

**Important:** Do not modify the generated plugins array. Only add `server.proxy`.

### 2-3. TypeScript Type Generation

Generate types while PocketBase is running:

```bash
npx pocketbase-typegen --url http://127.0.0.1:8090 --email admin@example.com --password yourpassword --out frontend/src/types/pocketbase-types.ts
```

Add an npm script to **`frontend/package.json`**:

```json
{
  "scripts": {
    "typegen": "pocketbase-typegen --url http://127.0.0.1:8090 --email admin@example.com --password yourpassword --out src/types/pocketbase-types.ts"
  }
}
```

> Confirm the superuser email and password with the user. Adjust `--url` to match the PocketBase URL.

**Details:** `Read references/typegen.md`

### 2-4. TanStack Query Configuration

Create a QueryClient and set up the Provider in the root component.

Edit **`frontend/src/routes/__root.tsx`**:

```tsx
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { Outlet, createRootRouteWithContext } from "@tanstack/react-router";

export interface RouterContext {
  queryClient: QueryClient;
}

export const Route = createRootRouteWithContext<RouterContext>()({
  component: RootComponent,
});

function RootComponent() {
  return <Outlet />;
}
```

Create the QueryClient in **`frontend/src/router.tsx`** (or `main.tsx`) and pass it to the router context:

```tsx
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { createRouter as createTanStackRouter } from "@tanstack/react-router";
import { routeTree } from "./routeTree.gen";

const queryClient = new QueryClient();

export function getRouter() {
  const router = createTanStackRouter({
    routeTree,
    scrollRestoration: true,
    defaultPreload: "intent",
    defaultPreloadStaleTime: 0,
    context: { queryClient },
  });
  return router;
}
```

> **Important:** Check the existing contents of `router.tsx` / `main.tsx` and integrate QueryClient while preserving existing configuration. The above is a pattern example — edit according to the generated file's code.

**Details:** `Read references/react-query-pocketbase.md`

### 2-5. Authentication Integration

If authentication is needed, configure the following:

1. **Auth context** — Create an AuthProvider in `frontend/src/lib/auth.tsx`
2. **Protected routes** — Authentication check using TanStack Router's `beforeLoad`
3. **Login page** — `frontend/src/routes/login.tsx`

**Details:** `Read references/auth-patterns.md`

## 3. Development Workflow

### Running PocketBase and Vite Simultaneously

**Terminal 1 (PocketBase):**

```bash
cd backend && ./pocketbase serve --http=127.0.0.1:8090
```

**Terminal 2 (Vite dev server):**

```bash
cd frontend && npm run dev
```

> In a Claude Code session, start PocketBase in the background:
> ```bash
> cd backend && nohup ./pocketbase serve --http=127.0.0.1:8090 > pb.log 2>&1 &
> ```

### Development Tips

- The Vite proxy eliminates CORS issues (operates as same-origin)
- Frontend changes are reflected instantly via HMR
- After PocketBase collection changes, regenerate types with `npm run typegen`
- The Admin UI is directly accessible at `http://127.0.0.1:8090/_/`

**Details:** `Read references/dev-and-deploy.md`

## 4. Deployment

### SPA Build → PocketBase pb_public Placement

In production, PocketBase serves the SPA directly (no separate web server needed):

```bash
# Build
cd frontend && npm run build

# Place in PocketBase's pb_public
cp -r frontend/dist/* backend/pb_public/
```

PocketBase automatically serves files from `pb_public/` and supports SPA client-side routing (non-existent paths fall back to `index.html`).

### Docker / Docker Compose / Reverse Proxy

For production deployment including Dockerfiles (binary mode & Go package mode), Docker Compose, Caddy/Nginx reverse proxy, and executable distribution:

**Details:** `Read references/deployment.md`

## 5. Setup Checklist

Verification items after scaffolding is complete:

- [ ] `npm run build` succeeds
- [ ] `src/lib/pocketbase.ts` has been created
- [ ] Proxy configuration has been added to `vite.config.ts`
- [ ] `components.json` exists (Shadcn UI initialized)
- [ ] QueryClient is configured (`__root.tsx` / `router.tsx`)
- [ ] PocketBase JS SDK can be imported (`import PocketBase from "pocketbase"`)
- [ ] `npm run typegen` generates types (when PocketBase is running)
- [ ] If authentication is needed: AuthProvider and protected routes are configured

## 6. Reference Index

| Topic | Reference |
|-------|-----------|
| TanStack Query + PB integration | `Read references/react-query-pocketbase.md` |
| Authentication patterns | `Read references/auth-patterns.md` |
| TypeScript type generation | `Read references/typegen.md` |
| Development workflow | `Read references/dev-and-deploy.md` |
| Production deployment (Docker, binary, proxy) | `Read references/deployment.md` |
| JS SDK details | `Read references/js-sdk.md` in the PocketBase skill |

