OneApp Docs
Core Concepts

Core Concepts

Master the fundamental concepts that make OneApp a powerful, scalable monorepo for building Next.js applications.

Why understand these concepts?

Working in a monorepo without understanding its architecture leads to problems:

  • Wrong dependencies — Adding packages to the wrong locations breaks builds
  • Type errors — Not using branded types causes ID mix-ups
  • Phantom dependencies — Dependencies leak between packages causing CI failures
  • Inefficient workflows — Don't know how to leverage workspace features

OneApp's architecture is built on pnpm workspaces (strict dependency management), shared packages (reusable code), team isolation (autonomous development), strict TypeScript (type safety), and modern tooling (ESLint 9, Vitest 4) — ensuring your applications are maintainable, testable, and scalable.

Production-ready with 40+ packages, TypeScript strict mode, branded types for ID safety, content-addressable storage (3x faster installs), and comprehensive testing infrastructure.

Core principles

OneApp is built on these key architectural decisions:

1. Code Sharing via Internal Packages

Share code across applications using scoped packages:

apps/web/app/page.tsx
import { Button } from "@repo/ui"; // Shared UI components
import { formatDate } from "@repo/utils"; // Common utilities
import type { UserId } from "@repo/types"; // TypeScript utilities

Benefits:

  • ✅ Single source of truth for shared code
  • ✅ Changes propagate automatically to all consumers
  • ✅ TypeScript provides type safety across packages

2. Workspace Isolation

Teams and individuals have dedicated spaces:

teams/ai/apps/         # AI team's applications
teams/ai/packages/     # AI team's shared packages
personal/andy/apps/    # Andy's personal projects

Benefits:

  • ✅ Teams control their own dependencies and tooling
  • ✅ No conflicts between team projects
  • ✅ Safe space for experimentation

3. Consistent Configuration

Shared configs ensure consistency across all packages:

apps/web/eslint.config.mjs
import reactConfig from "@repo/config/eslint/react";
export default [...reactConfig];
apps/web/tsconfig.json
{
  "extends": "@repo/config/typescript/nextjs.json"
}

Benefits:

  • ✅ Consistent code quality across teams
  • ✅ No configuration drift
  • ✅ Easy to update tooling for all packages

4. Type Safety with Branded Types

Prevent common type errors using branded types:

import { Brand } from "@repo/types";

type UserId = Brand<string, "UserId">;
type OrderId = Brand<string, "OrderId">;

function getUser(id: UserId) {
  /* ... */
}
function getOrder(id: OrderId) {
  /* ... */
}

const userId = "user_123" as UserId;
const orderId = "order_456" as OrderId;

getUser(orderId); // ❌ Compiler error: Type 'OrderId' is not assignable to 'UserId'

Benefits:

  • ✅ Prevents ID type mix-ups at compile time
  • ✅ Self-documenting code
  • ✅ Catches errors before runtime

5. Strict Dependency Management

pnpm prevents phantom dependencies:

package.json
{
  "dependencies": {
    "@repo/ui": "workspace:*", // Internal package
    "react": "^19.0.0" // External package
  }
}

Benefits:

  • ✅ No accidental access to transitive dependencies
  • ✅ Explicit dependency declarations
  • ✅ Reliable CI/CD builds

What you'll learn

Workspace Architecture

How pnpm organizes packages into logical groups:

  • Workspace patterns — Configure pnpm-workspace.yaml for your needs
  • Dependency resolution — How workspace:* protocol works
  • Best practices — Organizing packages for scalability

Dependency Management

Master pnpm's powerful dependency management:

  • Adding dependencies — To specific workspaces or the root
  • Internal dependencies — Using workspace:* protocol
  • Updating dependencies — Interactive updates and automation
  • Troubleshooting — Fix common dependency issues

Type Safety

TypeScript patterns for maximum safety:

  • Branded types — Prevent ID type confusion
  • AsyncResult pattern — Type-safe async operations
  • API response types — Standardized response structures
  • Type guards — Runtime type checking

Quick examples

Using shared packages

apps/web/app/dashboard/page.tsx
import { Button, Card } from "@repo/ui";
import { formatDate, formatCurrency } from "@repo/utils";
import type { UserId, AsyncResult } from "@repo/types";

export default async function DashboardPage() {
  const userId = "user_123" as UserId;
  const result: AsyncResult<User> = await fetchUser(userId);

  if (!result.success) {
    return <div>Error: {result.error.message}</div>;
  }

  return (
    <Card>
      <h1>Welcome, {result.data.name}</h1>
      <p>Member since {formatDate(result.data.createdAt)}</p>
      <p>Balance: {formatCurrency(result.data.balance)}</p>
      <Button>View Details</Button>
    </Card>
  );
}

Workspace filtering

# Build a package and all its dependencies
pnpm --filter=web... build

# Run tests for all packages in a directory
pnpm --filter="./packages/*" test

# Lint packages changed since main branch
pnpm --filter="[origin/main]" lint

Type-safe environment variables

apps/web/env.ts
import { createEnv } from "@t3-oss/env-nextjs";
import { z } from "zod/v4";

export const env = createEnv({
  server: {
    DATABASE_URL: z.string().url(),
    API_KEY: z.string().min(1)
  },
  client: {
    NEXT_PUBLIC_SITE_URL: z.string().url()
  },
  experimental__runtimeEnv: {
    NEXT_PUBLIC_SITE_URL: process.env.NEXT_PUBLIC_SITE_URL
  },
  skipValidation: !!process.env.SKIP_ENV_VALIDATION,
  emptyStringAsUndefined: true
});

// Usage
import { env } from "./env";

console.log(env.DATABASE_URL); // ✅ Works in server components
console.log(env.NEXT_PUBLIC_SITE_URL); // ✅ Works anywhere
console.log(env.API_KEY); // ❌ Error in client components

Key technologies

TechnologyVersionPurpose
pnpm10+Package management
TurborepoLatestTask orchestration
TypeScript5Type safety
ESLint9Linting (flat config)
Vitest4Testing
Husky9Git hooks
Prettier3Code formatting
ChangesetsLatestVersion management

Next steps

Ready to dive deeper?

  1. Workspace Architecture → — Understand pnpm workspaces
  2. Dependency Management → — Master pnpm commands
  3. Type Safety → — Learn TypeScript patterns

On this page