Project structure
What each folder in zap.ts holds, and the rule that decides where your own code should go.
zap.ts is a monorepo. A monorepo is one repository that holds several projects at once, instead of one repository for each.
There are three top folders.
zap.ts/
├── apps/ things you run and visit
├── packages/ shared code the apps import
└── tooling/ shared settings for tests and TypeScript
The pnpm-workspace.yaml file lists these three folders. That is how pnpm
knows they belong together.
apps/ — what you run
Each folder here is a separate website or server.
| Folder | What it is |
|---|---|
web |
Your product. Users sign in to reach it. Address: app.<domain> |
marketing |
Your public website: home page, blog, legal pages. Address: <domain> |
admin |
Your back office. Address: admin.<domain> |
api |
Your own public API, described with OpenAPI |
docs |
A documentation site for your own product |
emails |
A preview tool for your emails. It runs only on your computer |
web, marketing and admin are three separate apps on purpose. A visitor
reading your blog should not have to download your whole product first.
The back office keeps its own sign-in, separate from the web app.
api is for the public API you offer your customers. Your own app’s server
code does not go there. TanStack Start already runs server code inside web,
next to the page that needs it. See API.
packages/ — what the apps share
Each folder here is a library. Apps import them. Nothing is copied.
| Folder | What it does |
|---|---|
database |
Your tables, and the tool that talks to Postgres |
authentication |
Sign-in, teams, two-factor codes, passkeys |
authorization |
Who is allowed to do what |
billing |
Subscriptions and payments |
mail |
Sending email, and the email designs |
storage |
File uploads |
queues |
Work that runs later, in the background |
queues-cloudflare |
Runs that background work on Cloudflare |
queues-vercel |
Runs that background work on Vercel |
ai |
Talking to AI models |
analytics |
Seeing how people use your app |
flags |
Turning features on and off without a new release |
observability |
Catching and reporting errors |
environment |
Reading your settings and keys safely |
ui |
Buttons, forms, tables and the rest of the visual parts |
tanstack-start |
The shared setup every app uses to start up |
tooling/ — shared settings
This folder holds settings, not product code.
tsconfig— the shared TypeScript settings every project extends.testing— helpers for tests, such as a temporary test database.vite— shared build settings.
Where should my own code go?
Use this rule.
- Only one app needs it, and it will stay that way. Put it in that app.
- Two apps need it, or you can see that they soon will. Put it in a new
folder under
packages/.
Do not create a package for code with one user. Move it later, when a second app actually needs it.
See Adding a package for the steps.
How the parts refer to each other
Inside zap.ts, one package imports another by name:
"@zap-ts/database": "workspace:*"
workspace:* means “the copy in this repository”, not a version downloaded
from the internet.
Libraries from outside use a shared version list instead. See Dependencies.
Related
- Quickstart — get it running
- Adding a package — create a new shared package
- Dependencies — the rule for adding libraries
- Tech stack — what each part is built with