Skip to content

maxonchickdev/nodejs-monorepo

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

59 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

NodeJS Monorepo

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.

Workspace layout

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.jsonname).
  • 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";

Filesystem naming (repository-wide)

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/*/src
  • packages/*/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.


TypeScript symbols (all packages)

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 PascalCase object whose name ends with Constant, in *.constant.ts. Example: ConfigKeyConstant, EnvironmentsConstant in config-key.constant.ts, environments.constant.ts.
  • Primitive literals (timeouts, magic numbers shared across files) → UPPER_SNAKE when it improves scanability, or camelCase as const objects 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.


Backend (apps/backend)

Folders under src/

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.

File suffixes (Nest + this repo)

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)

ESM note

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.


Shared package (packages/shared)

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).

Web app (apps/web)

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.

Tooling (naming-adjacent)

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.

Checklist for new code

  1. Workspace name: @nodejs-monorepo/<pkg>; disk folder kebab-case under apps/ or packages/.
  2. Under apps/*/src or packages/*/src: directories and *.ts / *.tsxkebab-case; React exports PascalCase.
  3. Nest artifacts → suffix table above; DTO vs RDO filenames explicit.
  4. Cross-app contracts → packages/shared with PascalCase types.
  5. Grouped env/config keys → SomethingConstant in *.constant.ts.
  6. Run npm run lint:filesystem:check before pushing when you add files or folders.

About

NodeJS Monorepo

Topics

Resources

License

Stars

Watchers

Forks

Contributors

Languages