Reference Architecture Decisions ADR-0013: Code Organization — Server/Client Separation in Next.js App On this page
ADR-0013: Code Organization — Server/Client Separation in Next.js App
Status: Proposed
Date: 2025-11-08
Deciders: anchorpipe Core Program (rick1330)
Context
Next.js App Router supports both server and client components, but mixing server-only code (Node.js APIs, Prisma, next/headers) with client-safe code risks:
Accidental bundling of server code into client bundles (increasing bundle size)
Build-time errors when server-only imports are used in client components
Unclear boundaries for developers about what can be used where
ADR-0001 establishes Next.js as MVP BFF, with future migration to Rust/Go services (ADR-0007) when cutover criteria are met.
Clear code organization is needed to:
Support the "clear separation of concerns" principle from ADR-0001
Prepare for future service extraction (per ADR-0007)
Prevent build errors and bundle bloat
Improve developer experience with explicit boundaries
Decision
Server-only utilities are organized in apps/web/src/lib/server/:
Files using Node.js APIs (crypto, fs, etc.)
Prisma Client and database access
next/headers or next/server APIs
Environment variables (process.env)
Server-side only dependencies
Client-safe utilities remain in apps/web/src/lib/:
Pure functions (e.g., base64.ts)
Zod schemas (e.g., schemas/auth.ts)
Type definitions (e.g., rbac.ts - CASL abilities can be used client-side)
Validation utilities (e.g., validation.ts)
Test files are organized in __tests__/ directories:
lib/__tests__/ for client-safe utility tests
lib/server/__tests__/ for server-only utility tests
Tests import from parent directory using relative paths (e.g., import { ... } from '../oauth')
Consequences
Positive
Clear boundaries : Developers immediately understand what can be used in client vs. server contexts
Build safety : Prevents accidentally bundling server code into client bundles, maintaining <100KB gz entry bundle budget (ADR-0006)
Future-proofing : Server code is already separated, making extraction to Rust/Go services (ADR-0007) more straightforward
Developer experience : Explicit import paths (@/lib/server/...) make server-only code obvious
Test organization : __tests__/ directories keep source code clean while maintaining clear test-to-source relationships
Negative
Slightly longer import paths : @/lib/server/auth instead of @/lib/auth
Requires discipline : Developers must correctly categorize new utilities
Migration effort : Existing code needed refactoring (completed)
Neutral
No impact on runtime : This is purely organizational; no performance or functionality changes
No impact on ADR-0001 : This decision supports, not changes, the Next.js BFF approach
Alternatives Considered
Co-location with naming convention (e.g., auth.server.ts):
Rejected: Less discoverable, harder to enforce, doesn't prevent accidental imports
Separate lib/server/ and lib/client/ directories :
Rejected: Most utilities are server-only; client-safe code is the exception, not the rule
No separation (status quo):
Rejected: Risk of bundle bloat, unclear boundaries, harder future extraction
Revisit Criteria
If Next.js introduces better built-in mechanisms for server/client separation
If bundle size analysis shows server code is still being bundled (indicating enforcement gaps)
If future service extraction (ADR-0007) reveals this organization is insufficient
References