@repo/ ScopeAll internal packages use the @repo/ scope and are linked via pnpm's workspace:* protocol:
// apps/web/package.json
{
"dependencies": {
"@repo/ui": "workspace:*",
"@repo/trpc": "workspace:*",
"@repo/auth-next": "workspace:*"
}
}
This means imports always look like:
import { Button } from "@repo/ui/Button";
import { authenticatedProcedure } from "@repo/trpc/procedures";
import { patientsRepo } from "@repo/db";
Packages define explicit exports subpaths in their package.json instead of re-exporting everything from a single index.ts. This keeps bundle sizes small and makes dependencies clear.
@repo/db{
"exports": {
".": "./src/repos/index.ts",
"./schema": "./src/drizzle/schema/schema.ts",
"./db.types": "./src/db.types.ts",
"./supabase.types": "./src/lib/supabase.types.ts"
}
}
Consumers import specific subpaths:
import { patientsRepo } from "@repo/db"; // repos
import { zPatientId } from "@repo/db/schema"; // schema types
import type { PatientId } from "@repo/db/db.types"; // type helpers
@repo/trpc{
"exports": {
"./client": "./src/client.ts",
"./server": "./src/server.ts",
"./routers/*": "./src/routers/*.ts"
}
}
@repo/ui{
"exports": {
"./*": "./src/*.tsx",
"./composites": "./src/composites/index.ts",
"./hooks": "./src/hooks/index.ts"
}
}
This gives per-component imports like @repo/ui/Button, @repo/ui/Dialog, etc.
apps/web Cannot Import @repo/db DirectlyThe web app must not import the repo barrel (@repo/db) because it includes server-only code that would break client bundles. This is enforced via a Biome lint rule in biome.json:
{
"overrides": [{
"includes": ["apps/web/**"],
"linter": {
"rules": {
"style": {
"noRestrictedImports": {
"level": "error",
"options": {
"paths": {
"@repo/db": "Use @repo/db/schema or @repo/db/types instead. Direct imports may include server-only code."
}
}
}
}
}
}
}]
}
Use @repo/db/schema or @repo/db/db.types for type-level imports instead.
The @repo/db repos barrel (packages/db/src/repos/index.ts) is marked with server-cli-only, which prevents it from being imported in client-side code at build time. Packages containing server-only logic should follow this pattern.
Some packages export test utilities via a ./tests subpath so consumers can reuse mocks and helpers:
{
"exports": {
"./tests": "./__tests__/index.ts"
}
}
Used by @repo/ui, @repo/trpc, and others.
When adding a new package to the monorepo:
Create the folder under packages/:
packages/my-package/
├── src/
│ └── index.ts
├── package.json
└── tsconfig.json
Set up package.json:
{
"name": "@repo/my-package",
"version": "0.0.0",
"private": true,
"exports": {
".": "./src/index.ts"
},
"scripts": {
"check-types": "tsc --noEmit"
},
"devDependencies": {
"@repo/typescript-config": "workspace:*"
}
}
Extend the shared TypeScript config:
{
"extends": "@repo/typescript-config/base.json",
"compilerOptions": {
"outDir": "dist"
},
"include": ["src"]
}
Use @repo/typescript-config/react-library.json for packages that use React/JSX.
Add to consumer package.json in the app or package that needs it:
{
"dependencies": {
"@repo/my-package": "workspace:*"
}
}
Run pnpm install to link the new package.
Add a test script if the package will have tests, referencing @repo/vitest-config:
{
"scripts": {
"test": "vitest run",
"test:watch": "vitest"
},
"devDependencies": {
"@repo/vitest-config": "workspace:*"
}
}
Next: Web App Architecture