Skip to main content

Sharing pattern: what lives in shared vs frontends/shared

One place for the convention of what is shared across backend and frontends vs frontends-only. Two packages: shared (backend + all frontends; runtime-agnostic) and frontends/shared (frontends only; may use DOM/React).

What belongs where

shared

  • API response envelope types and zod schemas (e.g. api-response). See responses.
  • DTOs and schemas used by backend validation and frontend forms (create/update, filter/query). See schemas, requests.
  • Shared domain types or model shapes. See models.
  • Serialization DTOs (e.g. class-transformer shapes). See serialization.
  • No Node-only or DOM-only APIs; no NestJS, React, or Vite imports. Keeps the package consumable by both backend and frontends.

frontends/shared

  • API client (handleRequest, axios instance). See http-client, responses.
  • UI helpers (e.g. cn for class names).
  • Shared React components, frontend-only hooks or utils.
  • May depend on shared (e.g. ApiResponse from shared/api-response).

Adding and consuming shared code

shared

  • Add source under shared/src/<name>.ts. The package’s subpath exports make it available as shared/<name> without changing package.json. Optionally re-export from shared/src/index.ts for the root barrel.
  • Build with pnpm --filter shared run build (or via root pnpm build). See monorepo for build order and dev watch.

frontends/shared

  • Add under frontends/shared/src/ (e.g. src/lib/<name>.ts). Import as frontends-shared/lib/<name> (or other subpaths per package exports). Subpath pattern; no per-file export entries needed.

Consumption

  • Backend and frontends depend on shared via "shared": "workspace:*"; frontends also depend on "frontends-shared": "workspace:*". Consume built output from dist/; no TypeScript path mapping. See monorepo and static-typing for build order and tsconfig.

Implementation

shared: The shared package has a root entry (.dist/index.js) and a subpath pattern (./*dist/*.js) in package.json exports. Key files: shared/src/api-response.ts (envelope types and fieldErrorsSchema), shared/src/index.ts (root barrel, e.g. app name and greeting). New modules under shared/src/<name>.ts are importable as shared/<name> without adding export entries.

frontends/shared: The frontends/shared package has root and subpath exports (./*, ./*/*) so modules under frontends/shared/src/ are importable by path (e.g. frontends-shared/lib/api, frontends-shared/lib/utils). The boilerplate provides lib/api.ts (handleRequest, axios instance), lib/utils.ts (cn), and index.ts (e.g. Logo). No new package.json entries needed when adding files under src/.

The generation skill creates both packages and these export shapes; this section documents how the boilerplate implements the sharing pattern.

References

  • Stack: monorepo (workspace layout, build, dev), static-typing (shared tsconfig, consumption).
  • Patterns: responses (envelope in shared), requests (validation + shared), schemas (create/update and filter schemas in shared), models (in shared), serialization (shared DTOs).