Lazy Initialization
Never initialize external clients at the top level. Next.js hates it during build. Always use getters.
Defensive Configuration
Environment variables are ghosts during build time. Always provide a fallback to prevent the "undefined" crash.
The Entity Contract
Updating the UI? Update the Entity first. In a monorepo, the Domain is the source of truth for every team.
Modular Monolith
Keep features logically separated but physically close. Each module (Billing, Auth, Tenant) stays independent within the monorepo.
Layered Model
Follow the flow: Infrastructure depends on Application, and Application depends on Domain. Never the other way around. Keep your Domain pure.
Shared Foundation
Stop repeating yourself. Build it once in @repo/ui or @repo/domain and consume it across 10+ different SaaS apps.
Dependency Injection
Don't use new Service() in your components. Inject them via IoC Container for better testability and decoupled logic.
Strategic Casting
TypeScript is your friend, not your jailer. Use any sparingly to bridge build inconsistencies, but always target explicit types.
tRPC Type Safety
Bridge your client and server with 100% type safety. No more manual API fetching; just call your procedures like local functions.
Centralized Configs
Keep your Tailwind, TypeScript, and ESLint configs in one place (packages/config-*). Update once, reflect everywhere.