npm workspaces monorepo: deployable apps under apps/, reusable libraries under packages/. This document is the source of truth for naming and layout; tooling (Biome, ls-lint, Knip) should stay aligned with it.
| Path | npm name |
Role |
|---|---|---|
apps/backend |
@nodejs-monorepo/backend |
NestJS API, Prisma, feature modules |
apps/web |
@nodejs-monorepo/web |
Vite + React SPA |
packages/shared |
@nodejs-monorepo/shared |
Types and other cross-app, runtime-safe code |
Rules
- Every workspace package uses the
@nodejs-monorepo/*scope (package.json→name). - New runnable deployables →
apps/<name>/(short role name,kebab-case), e.g.admin,worker-notifications. - New libraries →
packages/<name>/(capability-oriented,kebab-case), e.g.eslint-config,ui.
Imports across boundaries use package names only, never deep relative hops between apps:
import type { SignInType } from "@nodejs-monorepo/shared";| What | Convention | Enforcement |
|---|---|---|
Directories under workspace src/ |
kebab-case |
health-checks/, sign-in/, rate-limit/ |
Files .ts / .tsx under apps/*/src and packages/*/src |
kebab-case stem |
auth.service.ts, sign-up.dto.ts, sign-in.route.tsx, config-key.constant.ts |
| Root / tooling filenames | Ecosystem defaults | biome.json, docker-compose.yml, Dockerfile.backend, commitlint.config.ts |
ls-lint (.ls-lint.yml) applies kebab-case to .dir, .ts, and .tsx under:
apps/*/srcpackages/*/src
Ignored paths include node_modules, dist, .git, and **/prisma/migrations/** (Prisma timestamp folder names).
React: file names stay kebab-case (same as Nest modules). Exported route/component identifiers are PascalCase (e.g. SignInRoute in sign-in.route.tsx). Do not use PascalCase.tsx filenames in src/—that diverges from backend and breaks a single filesystem rule.
Tests: co-locate *.spec.ts / *.test.ts next to the module under test, or use __tests__/—pick one style per package and keep it consistent.
| Kind | Style | Examples in this repo |
|---|---|---|
| Classes (Nest providers, DTOs, RDOs, guards, entities) | PascalCase |
AuthService, SignInDto, AuthRdo |
| Types / interfaces | PascalCase |
AuthPayload, SignInType, EnvironmentType |
| Functions, methods, variables, properties | camelCase |
signUp, configService, accessToken |
| Booleans | is / has / can / should prefix |
isEnabled, hasSession |
| Enum type | PascalCase |
OrderStatus |
| Enum members | PascalCase preferred (matches typical TS + Swagger usage) |
Pending, Active — if you introduce UPPER_SNAKE members, keep them consistent within that enum |
Constants
- Fixed key maps / grouped config tokens → export as a
PascalCaseobject whose name ends withConstant, in*.constant.ts. Example:ConfigKeyConstant,EnvironmentsConstantinconfig-key.constant.ts,environments.constant.ts. - Primitive literals (timeouts, magic numbers shared across files) →
UPPER_SNAKEwhen it improves scanability, orcamelCaseas constobjects for grouped defaults—prefer one approach per file.
Barrel files in a feature folder use a short plural topic matching siblings: dtos.ts, rdos.ts, types.ts, constants.ts, guards.ts, strategies.ts, interceptors.ts, filters.ts, decorators.ts. Re-export named exports explicitly; keep barrels shallow (avoid index.ts chains that obscure bundle entry points).
Helpers (“utils”) → only for generic, domain-agnostic pure functions (formatting, small assertions). Feature rules belong under modules/<feature>/ next to that feature’s service/repository—not in a dumping ground called helpers.ts.
| Folder | Purpose |
|---|---|
modules/ |
Vertical features: modules/<feature>/ (e.g. auth/). One Nest *.module.ts per feature slice when it’s a bounded context. |
core/ |
Infrastructure wired as Nest modules: Prisma, Redis, JWT, S3, rate limiting, config, health checks, registrations under core/config/registers/. |
common/ |
Cross-feature primitives: decorators, guards, strategies, interceptors, filters, shared types, constants. |
| Pattern | Role |
|---|---|
<feature>.module.ts |
Nest module |
<feature>.controller.ts |
HTTP controller |
<feature>.service.ts |
Injectable application service |
<feature>.repository.ts |
Data access |
<name>.dto.ts |
Request / input DTO (validation, Swagger) |
<name>.rdo.ts |
Response DTO (RDO—serialized API output) |
<name>.guard.ts |
Auth / policy guard |
<name>.strategy.ts |
Passport strategy |
<name>.interceptor.ts |
Interceptor |
<name>.filter.ts |
Exception filter |
<name>.decorator.ts |
Custom decorator |
<name>.type.ts |
Shared TS-only types (not tied to a single class file) |
<name>.register.ts |
Joi/env registration helpers in core/config/registers/ |
prisma/schema.prisma, prisma/migrations/ |
Schema and migrations (migration folder names = Prisma default: timestamp + snake_case slug) |
prisma/seeders/ |
Seed scripts (kebab-case .ts files when you add more than seeder.ts) |
Production build uses "type": "module" with relative imports that often include .js extensions targeting emitted files (see Nest/tsconfig). Match existing import style when adding files.
| Topic | Rule |
|---|---|
| Purpose | Code safe for both backend and frontend (no Node-only APIs, no Nest/DOM leakage unless split entry points). |
| Layout | src/types/<domain>/ (e.g. types/auth/), src/index.ts as the package entry barrel. |
| Type names | PascalCase (SignInType, SignUpType). |
| Files | kebab-case, multi-word segments joined with hyphens (sign-in.type.ts). |
| Area | Convention |
|---|---|
| Routes | src/routes/<segment>/<segment>.route.tsx mirroring URL segments (kebab-case dirs + file stem). |
| Exported route component | PascalCase symbol matching the page (SignInRoute). |
| Entry | src/main.tsx, Vite index.html (entries also referenced in knip.config.ts). |
| Future UI | Optional src/components/ with kebab-case.tsx files (e.g. primary-button.tsx) exporting PascalCase components, or one folder per component primary-button/index.tsx—choose one pattern for the whole app. |
| Tool | Role |
|---|---|
| Biome | Formatter + linter (root / per-package biome.json). |
| ls-lint | kebab-case dirs and .ts / .tsx under workspace src/ trees (see above). |
| Knip | Unused exports/deps; entry globs in knip.config.ts. |
- Workspace
name:@nodejs-monorepo/<pkg>; disk folderkebab-caseunderapps/orpackages/. - Under
apps/*/srcorpackages/*/src: directories and*.ts/*.tsx→kebab-case; React exportsPascalCase. - Nest artifacts → suffix table above; DTO vs RDO filenames explicit.
- Cross-app contracts →
packages/sharedwithPascalCasetypes. - Grouped env/config keys →
SomethingConstantin*.constant.ts. - Run
npm run lint:filesystem:checkbefore pushing when you add files or folders.