# Local setup

Configure a clone without overwriting an existing project’s identity or credentials.

## Prerequisites [#prerequisites]

Use the repository’s pnpm version (`packageManager` in the root manifest), a supported Node runtime (CI uses Node 24), Git and a local Postgres installation for integration tests. Native development additionally needs the platform toolchain and a compatible Expo development client.

<Steps>
  <Step title="Install the workspace">```sh pnpm install --frozen-lockfile ```</Step>
  <Step title="Configure the project">
    ```sh pnpm setup pnpm doctor ``` Setup covers identity, environment files and the selected
    database/Cloudflare providers. For an existing clone, preserve its identity and credentials and
    repair only missing configuration.
  </Step>
  <Step title="Apply migrations and start">
    ```sh pnpm db:migrate pnpm dev:web # In another terminal, when needed: pnpm dev:mobile ```
  </Step>
</Steps>

## Local PostgreSQL [#local-postgresql]

Any PostgreSQL 16 or newer works; Neon is only one host. To develop without a hosted database, run one in Docker (or Homebrew) and connect as a table owner that can create roles:

```sh
docker run -d --name template-postgres -e POSTGRES_PASSWORD=postgres -p 127.0.0.1:5432:5432 postgres:17
docker exec template-postgres psql -U postgres \
  -c "CREATE ROLE template_owner LOGIN CREATEROLE CREATEDB PASSWORD 'template'" \
  -c "CREATE DATABASE template_dev OWNER template_owner"
```

Set `DATABASE_URL=postgresql://template_owner:template@127.0.0.1:5432/template_dev` in `apps/web/.env` (and `.dev.vars` for `wrangler dev`), then `pnpm db:migrate`. Put it in the env file rather than the shell: `pnpm run dev` goes through Turbo, which does not pass undeclared shell variables to the dev server. The first migration creates the `app_tenant` role that row-level security switches to; connecting as the stock `postgres` superuser also works. If your role cannot create roles, the migration prints the two statements an administrator must run once.

For the built Worker, Hyperdrive needs a local override with a password, e.g. `CLOUDFLARE_HYPERDRIVE_LOCAL_CONNECTION_STRING_HYPERDRIVE=postgresql://template_owner:template@127.0.0.1:5432/template_dev`, or `localConnectionString` on the `hyperdrive` entry of an uncommitted Wrangler config. Row-level security behaves the same with and without Hyperdrive; see [tenant isolation](/docs/features/database#tenant-isolation).

## Local runtime [#local-runtime]

The web dev server defaults to port 3005 and uses Nitro/Node, not workerd. The production build uses the Cloudflare plugin. A successful dev request alone does not validate Worker compatibility. Use the [built-Worker checks](/docs/development/testing) for changes to server dependencies.

Parallel worktrees need separate ports and isolated databases. Set an explicit dev-server port, adjust the public server URL used by mobile, and stop only processes you started. Do not run migrations against another lane’s database.

## Common setup failures [#common-setup-failures]

Missing credentials belong in the correct [environment file](/docs/development/environments). A stale development client needs rebuilding after native dependency changes. A database history mismatch needs investigation, not `db:push`. Start with `pnpm doctor` and the existing setup skill before manually rewriting project identifiers.

## Key files [#key-files]

- [`packages/project-setup-cli/src/index.mjs`](https://github.com/CarlosZiegler/template-cloudflare/blob/main/packages/project-setup-cli/src/index.mjs)
- [`.agents/skills/setup-envs/SKILL.md`](https://github.com/CarlosZiegler/template-cloudflare/blob/main/.agents/skills/setup-envs/SKILL.md)
- [`.agents/skills/startup/SKILL.md`](https://github.com/CarlosZiegler/template-cloudflare/blob/main/.agents/skills/startup/SKILL.md)

