Code conventions
Formatter: oxfmt (not Prettier)
Section titled “Formatter: oxfmt (not Prettier)”Nexus uses oxfmt (part of the Oxc toolchain), not Prettier. Running the wrong formatter will produce diffs on every file.
pnpm oxfmt --write . # Format all filespnpm oxfmt --check . # Check (CI uses this)CI fails if any file is not oxfmt-formatted.
Linter: oxlint
Section titled “Linter: oxlint”pnpm oxlint .oxlint is fast (Rust-based) and is the only linter configured. ESLint is not used.
TypeScript
Section titled “TypeScript”- Version: 6.0.3
- Strict mode: on across all packages
- Per-package typecheck:
pnpm --filter <pkg> typecheck - CI typecheck: Turbo-affected (only typechecks changed packages + their consumers)
- scheduler-api tsc memory: requires
NODE_OPTIONS=--max-old-space-size=6144on CI (2-vCPU runner OOMs otherwise)
Import style
Section titled “Import style”Direct imports only — no re-export barrel files.
// ✅ Correctimport { Button } from '@nexus/ui/components/button';
// ❌ Wrong — don't create or use barrelsimport { Button } from '@nexus/ui';After moving a file, update all import sites to the new path. Do not add a re-export shim at the old path for “stability.”
pnpm script naming
Section titled “pnpm script naming”Never name a script up, add, remove, or install — these shadow pnpm
built-in commands silently:
// ❌ These will never run{ "scripts": { "up": "docker compose up", "install": "…" } }
// ✅ Use descriptive names{ "scripts": { "infra:up": "docker compose up", "db:install": "…" } }UI components
Section titled “UI components”@nexus/ui uses zero custom CSS classes. All styling goes through:
- Tailwind utility classes
@layer basefor element resets
/* ✅ Element resets go in @layer base */@layer base { * { box-sizing: border-box; }}
/* ❌ Custom class outside @layer base breaks component styles */.my-reset { box-sizing: border-box;}Comments
Section titled “Comments”Write comments only when the why is non-obvious — a hidden constraint, a subtle invariant, a workaround. Do not comment what the code does (the code does that). Do not reference task names, issue numbers, or callers in code comments.
SDK error handling
Section titled “SDK error handling”WorkOS SDK @throws declarations are unreliable in production — the SDK may
throw a different exception type than documented. Always use message regex
fallback alongside status code checks:
// ✅ Robust WorkOS error detectionfunction isInvitationAlreadyExistsError(err: unknown): boolean { return ( err instanceof UnprocessableEntityException || (err instanceof GenericServerException && /already.*invited/i.test(err.message)) );}Drizzle enum constraint
Section titled “Drizzle enum constraint”Never ADD an enum value and USE it in the same migration file — PostgreSQL rejects new-value use before the transaction commits:
-- ❌ Both in one migration file: PG rejects thisALTER TYPE booking_status ADD VALUE 'waitlisted';UPDATE booking SET status = 'waitlisted' WHERE …; -- fails!
-- ✅ Split across two separate migration files-- Migration 001: ALTER TYPE booking_status ADD VALUE 'waitlisted';-- Migration 002: UPDATE booking SET status = 'waitlisted' WHERE …;See Database conventions for more migration rules.