Project Structure
Relevant source files
The following files were used as context for generating this wiki page:This project is a full-stack TypeScript monorepo managed with pnpm workspaces and Turborepo. The structure is designed to enforce a clean separation of concerns between different applications and shared libraries, promoting code reuse and type safety across the entire stack. The core principle is a "contract-based" approach, where a shared contract package defines the API data structures, ensuring that the frontend and backend are always in sync.
The repository is organized into two main directories: apps for deployable applications and packages for shared code, libraries, and configurations. This modular structure is orchestrated by Turborepo for high-performance builds and development workflows.
Sources: README.md:29-37
Monorepo Organization
The project follows a standard monorepo layout, separating applications from shared packages. This is defined in the project's README.md and managed by pnpm workspaces.
Sources: README.md:29-37
contract-based-monorepo/
├── apps/ # Application code
│ ├── api/ # Hono API server with ORPC
│ └── web/ # React frontend with TanStack Router
│
├── packages/ # Shared packages
│ ├── contract/ # API contracts and schemas
│ ├── db/ # Database schema and access layer
│ └── ui/ # Shared UI components
│
└── .env # Environment variables (create from example)
Sources: README.md:29-37
Workspaces
The monorepo consists of several distinct workspaces, each with a specific role.
| Workspace | Location | Description |
|---|---|---|
@contract-based-monorepo/api | apps/api | Hono-based API server implementing the ORPC contract. |
@contract-based-monorepo/web | apps/web | React frontend application using TanStack Router. |
@contract-based-monorepo/contract | packages/contract | Defines shared API contracts and Zod schemas. |
@contract-based-monorepo/db | packages/db | Contains the Drizzle ORM schema and database logic. |
@contract-based-monorepo/ui | packages/ui | Shared React UI components built with Radix UI. |
Sources: README.md:31-37, apps/api/package.json:2, apps/web/package.json:2, packages/contract/package.json:2, packages/db/package.json:2, packages/ui/package.json:2
The following diagram illustrates the dependencies between the workspaces.
This diagram shows that the web application depends on the shared ui package, while the api application depends on both the contract and db packages.
Sources: apps/web/package.json:13, apps/api/package.json:15-16
Contract-Based Architecture
A key architectural feature is the use of a shared contract package. This package defines the data structures and API schemas using Zod, creating a single source of truth for the data exchanged between the frontend and backend.
This approach provides end-to-end type safety. The api server uses these schemas to validate requests and structure responses, while the web client can use the same types for type-safe data fetching and form management.
Sources: README.md:1, packages/contract/package.json, packages/contract/src/schemas/planet.ts
Schema Definition
Schemas are defined in the packages/contract workspace using Zod. For example, the Planet entity has schemas for creation, updates, and the final data model.
// packages/contract/src/schemas/planet.ts
import { oz } from "@orpc/zod";
import { z } from "zod";
import { UserSchema } from "./user";
export const NewPlanetSchema = z.object({
name: z.string(),
description: z.string().optional(),
image: oz.file().type("image/*").optional(),
});
export const PlanetSchema = z.object({
id: z.number().int().min(1),
name: z.string(),
description: z.string().optional(),
imageUrl: z.string().url().optional(),
creator: UserSchema,
});
Sources: packages/contract/src/schemas/planet.ts:1-24
Data Flow
The contract ensures a consistent data flow from the database to the user interface.
This sequence shows how the contract package serves as the central point of agreement for data shapes between the api and web applications.
Sources: apps/api/package.json:15, apps/web/package.json:13, packages/contract/src/schemas/planet.ts, apps/api/src/middlewares/db.ts:1-6
Build System and Tooling
The monorepo's development experience and build process are managed by a combination of Turborepo, Biome, and TypeScript.
Turborepo
Turborepo is the high-performance build system used to manage tasks across the monorepo. It orchestrates scripts like build, dev, and type:check, caching outputs to speed up subsequent runs.
Sources: package.json:10-16, turbo.json
The configuration in turbo.json defines the task pipeline:
// turbo.json
{
"$schema": "https://turbo.build/schema.json",
"ui": "tui",
"tasks": {
"build": {
"dependsOn": ["^build"],
"inputs": ["$TURBO_DEFAULT$", ".env*"],
"outputs": [".cache/tsbuildinfo.json", "dist/**"]
},
"type:check": {
"dependsOn": ["^build"],
"outputs": [".cache/tsbuildinfo.json"]
},
"dev": {
"cache": false,
"persistent": true
}
}
}
Sources: turbo.json:1-19
Key tasks include:
build: Depends on thebuildtask of its dependencies (^build) and caches thedistdirectory.type:check: Runs TypeScript checks across the workspace.dev: Runs development servers, with caching disabled for a live-reloading experience.
Linting and Formatting
The project uses Biome for fast linting and formatting, replacing the need for ESLint and Prettier. The configuration is centralized in biome.json.
Sources: README.md:62, biome.json
The biome.json file specifies rules, formatting options, and files to ignore.
// biome.json
{
"formatter": {
"enabled": true,
"indentStyle": "space",
"indentWidth": 2
},
"linter": {
"enabled": true,
"rules": {
"recommended": true
}
}
}
Sources: biome.json:14-25
Root package.json scripts are provided to run Biome across the entire project:
pnpm lint: Lints and auto-fixes issues.pnpm format: Formats all files.pnpm check: Runs both linting and formatting.
Sources: package.json:13-15
TypeScript Configuration
A base tsconfig.base.json file provides a common set of compiler options for all workspaces in the monorepo. This ensures consistency and enables strict type-checking rules project-wide.
Key settings include:
"target": "ES2022": Compiles to modern JavaScript."strict": true: Enables all strict type-checking options."module": "ES2022"and"moduleResolution": "bundler": Configured for modern ESM projects that use a bundler."noEmit": true: Preventstscfrom outputting JavaScript files, leaving transpilation to the bundler (e.g., Vite).
Sources: tsconfig.base.json