---
title: "Project structure"
description: "The turborepo the cli generates."
url: https://plate.findmalek.engineer/docs/project-structure
markdown: https://plate.findmalek.engineer/docs/project-structure.md
group: "Start"
---

# Project structure

**my-app/**

```text
├─ apps/
│  ├─ web/  # hero landing, next
│  ├─ dashboard/  # better-auth login and app shell, next
│  ├─ api/  # orpc on bun
│  └─ docs/  # optional module, fumadocs on next
├─ packages/
│  ├─ ui/  # shadcn components and theme tokens
│  ├─ common/  # shared zod schemas, constants and utils
│  ├─ orpc/  # procedures and clients, built on common
│  ├─ db/  # drizzle schema, migrations, seed scenario
│  ├─ auth/  # better-auth setup
│  ├─ env/  # zod-validated env, one root .env
│  ├─ config/  # shared config
│  ├─ storage/  # optional module
│  └─ ai/  # optional module
├─ docker/  # local postgres compose file
├─ .env  # generated, with secrets filled in
└─ turbo.json
```

## Core and modules

The core is fixed and always generated: the apps `api`, `web` and `dashboard`, and the packages `ui`, `orpc`, `db`, `auth`, `env`, `common` and `config`. Everything else is a [module](https://plate.findmalek.engineer/docs/modules.md): storage, AI, docs, notifications, analytics and so on. Modules are grouped, and the `minimal`, `standard` and `everything` profiles are just named sets of them, so you start from one and tweak.

## One rule for the apps

`apps/api` is the only app that touches the database, auth, storage and providers. `web` and `dashboard` only call the api, so secrets and data access live in one place and the two frontends stay thin.

## Shared code lives in common

`packages/common` holds what more than one app or package needs: zod schemas and their inferred types, constants such as input limits, and small utils. The api validates with the same schemas the dashboard forms read their limits from, so a rule changes in one file. Import from `@your-scope/common/schemas`, `/constants` or `/utils`; don't redeclare a type in an app when one exists there.

## Commands

| Command | What it does |
| --- | --- |
| `pnpm dev` | all apps |
| `pnpm dev:web` | web and api |
| `pnpm dev:dashboard` | dashboard and api |
| `pnpm build` | build everything with turbo |
| `pnpm check` | biome format and fix |
| `pnpm lint` | biome and oxlint, no fixes |
| `pnpm check-types` | typescript across the repo |
| `pnpm db:up` / `db:down` | local postgres |
| `pnpm db:generate` / `db:migrate` / `db:seed` / `db:studio` | drizzle |
| `pnpm ui:add <component>` | add a shadcn component to `packages/ui` |

## Environment

One `.env` at the root feeds every app, validated by `packages/env`. The cli generates it from `.env.example` with secrets filled in. Keys for modules you turned off are removed.
