---
title: "Development"
description: "Run Parsew locally, the checks every change passes, and the end-to-end tests."
---

```bash
pnpm install
pnpm db:migrate:local   # the local D1 database
pnpm dev                # http://app.localhost:5173
```

`pnpm dev` builds these docs when they changed, then starts Vite with the Worker inside it (`@cloudflare/vite-plugin`). All three surfaces are served:

| URL | Surface |
| --- | --- |
| `http://app.localhost:5173` | Dashboard ("Continue in local dev" signs in without a password) |
| `http://logo.localhost:5173/{domain}?token=pk_…` | Image API |
| `http://localhost:5173` | Landing page |
| `http://localhost:5173/docs` | Docs |

`PARSEW_SITE=off pnpm dev` serves no landing page (like a default self-hosted deployment): the docs move to `app.localhost:5173/docs`. `PORT=5174 pnpm dev` changes the port.

Local bindings: D1, R2 and the edge cache persist in `.wrangler/state`; Images transforms run through sharp. Miniflare's Analytics Engine keeps nothing, so under `vite dev` the usage data points are also kept in memory and the dashboard reads them from there (see `src/server/usage/usage.ts`). Billing is off unless `AUTUMN_SECRET_KEY` is set (in `.dev.vars` or the environment). `pnpm dev` ignores `.env`, where `atmn login` keeps the Autumn keys; `pnpm dev:billing` loads it, so the dashboard and metering run against the Autumn sandbox.

## Checks

```bash
pnpm verify   # pnpm check (Ultracite/Oxlint) + pnpm typecheck + pnpm build
```

## End-to-end tests

End-to-end scenarios are the only tests. They drive the dev server with real Chrome; see `e2e/README.md` in the repository.

## Changing the schema

Add a numbered file in `migrations/`. When Better Auth's options change, `pnpm db:auth-schema` prints the tables it needs.
