Project Structure

Getting StartedArchitecture guideReadable boundaries

The template follows a route-first structure in src/app, with supporting layers for configuration, shared UI, and backend services.

The goal of this layout is not only to keep files organized. It is to make the codebase easier to read, easier to extend, and easier to maintain as your product grows.

How to read this page

Start with the high-level map, then use the placement rules to decide where new code should live before you create files in the wrong layer.

Codebase map

High-level map

src
app# Pages, layouts, route handlers, route-local composition
[locale]# Localized routes
(home)# Marketing site
auth# Sign in, sign up, forgot password
dashboard# Protected app area
payment# Checkout result pages
components
ui# Primitive UI only
shared# Navigation, branding, and cross-cutting components
config# Brand, content, navigation, and integration settings
features# Feature-specific reusable UI
i18n# Locale routing and message loading
server
api# tRPC routers and procedures
services# Business logic for domains like auth and billing
trpc# Client and server tRPC wiring

Why the structure matters

When each layer has a clear responsibility, it becomes easier to know where to add new code and where not to.

Routes stay focused

Pages, layouts, and route-local composition remain close to the app entry points instead of becoming a home for every kind of logic.

UI stays readable

Primitive components, shared components, and feature-specific pieces stay separated so the design system does not mix with product logic.

Configuration stays centralized

Brand, navigation, content, and integration defaults live in predictable config surfaces instead of being scattered through routes.

Business logic stays reusable

Server-side logic can evolve independently from pages and transport layers when it lives in services instead of inside route files.

Practical rule

If a piece of code can be reused outside a single route, it usually should not be buried inside a page file.

Placement rules

Placement rules

src/app

Use this layer for:

  • page.tsx, layout.tsx, loading.tsx, error.tsx
  • Route handlers in app/api
  • Route-local UI composition

Avoid putting domain logic here when it can live in src/server/services.

src/components/ui

Use for unopinionated primitives and design-system level building blocks.

src/features

Use for reusable UI tied to a product area, such as marketing-specific components or auth forms.

src/content

Use for content collections and their schemas (e.g. blog posts, changelog entries).

src/server/api

Use for tRPC routers, procedure definitions, and transport-level concerns.

src/server/services

Use for business logic that should not be coupled to a route or a tRPC router.

Good separation

A route should decide what to render. A service should decide how a business process works. A router should decide how that behavior is exposed.

Examples in the current codebase:

  • src/server/services/billing/checkout.ts
  • src/server/services/billing/webhook-sync.ts
  • src/server/services/billing/customer.ts