Project Structure
tsdevstack uses a monorepo structure where all your applications, packages, and infrastructure live together. This makes it easy to share code, manage dependencies, and deploy consistently.
Directory overview
my-project/
├── apps/
│ ├── auth-service/ # Backend NestJS service
│ ├── bff-service/ # Backend-for-frontend service
│ ├── offers-service/ # Another backend service
│ ├── frontend/ # Next.js application
│ └── react-app/ # SPA (Rsbuild/Vite)
├── packages/ # Shared code
│ ├── auth-service-client/ # Generated HTTP clients + DTOs
│ └── nest-common/
├── infrastructure/
│ ├── kong/ # Generated gateway image (Dockerfile) + per-env cloud kong.yml
│ └── terraform/ # Cloud deployment configs
│ └── dev/ # Per-environment Terraform
├── kong-plugins/ # Your custom Kong plugins (optional)
├── .tsdevstack/ # Framework configuration
│ ├── config.json # Main project config
│ └── infrastructure.json # Infrastructure settings
├── .secrets.tsdevstack.json # Framework-generated secrets (git-ignored)
├── .secrets.user.json # Your custom secrets (git-ignored)
├── .secrets.local.json # Merged output (git-ignored)
├── docker-compose.yml # Generated - local orchestration
├── kong.tsdevstack.yml # Generated - gateway config
├── kong.user.yml # Your gateway overrides
├── kong.yml # Merged gateway config
└── package.json # Root workspace config (npm workspaces)
Key directories
apps/
All applications live directly under apps/. Backend services, workers, and frontends are all peers:
apps/
├── auth-service/ # NestJS backend
├── bff-service/ # NestJS backend
├── offers-service/ # NestJS backend
├── frontend/ # Next.js app
└── react-app/ # SPA
Backend services (NestJS)
Each backend service is a standalone NestJS application using a module-based structure:
apps/auth-service/
├── prisma/
│ ├── schema.prisma # Database schema
│ ├── migrations/ # Database migrations
│ └── seed.ts # Seed data
├── docs/
│ └── openapi.json # Generated OpenAPI spec
├── scripts/
│ └── generate-openapi.ts # OpenAPI generation script
├── src/
│ ├── main.ts # Application entry point
│ ├── app.module.ts # Root NestJS module
│ ├── auth/ # Feature module
│ │ ├── auth.module.ts
│ │ ├── auth.controller.ts
│ │ ├── auth.service.ts
│ │ └── dto/ # Module-specific DTOs
│ ├── user/ # Another feature module
│ ├── prisma/ # Prisma service module
│ ├── processors/ # BullMQ job processors
│ ├── worker.ts # Worker entry point
│ └── worker.module.ts # Worker module
├── test/ # E2E tests
├── package.json
└── tsconfig.json
NestJS services use feature modules - each module (auth, user, etc.) contains its own controllers, services, and DTOs. Services are exposed through Kong gateway with route paths generated from OpenAPI decorators.
Workers
Workers handle background job processing within a service. They live inside the service folder and share its codebase:
apps/auth-service/
├── src/
│ ├── main.ts # Service entry point
│ ├── app.module.ts # Main service module
│ ├── worker.ts # Worker entry point
│ ├── worker.module.ts # Worker module
│ └── processors/ # Job processing logic
├── package.json
└── tsconfig.json
By default, workers run in the same container as the service. For independent scaling, register them as detached workers:
npx tsdevstack register-detached-worker --name email-worker --base-service auth-service
Workers can process queues, handle scheduled tasks, or run long operations without blocking API responses.
Frontends
Web applications (Next.js or SPA) live alongside services:
apps/frontend/
├── src/
│ ├── app/ # Next.js app directory
│ ├── components/ # React components
│ └── lib/ # Utilities
├── public/ # Static assets
├── package.json
└── next.config.js
Frontends can use generated DTOs from services for type-safe API calls.
packages/
Shared code and generated clients:
packages/
├── auth-service-client/ # Generated from auth-service
│ ├── src/ # HTTP client + types
│ ├── dto/ # DTO classes with decorators
│ └── dist/ # Built output
└── nest-common/ # (Optional) Shared backend utilities
Service client packages (*-client/) are auto-generated when you run npx tsdevstack generate-openapi. The nest-common package is an example of a shared library you can create for code reused across services — it's not generated by the framework.
Import generated clients in any app:
// HTTP client for API calls
import { Api } from '@shared/auth-service-client';
// DTOs for NestJS services
import { UserDto } from '@shared/auth-service-client/dto';
infrastructure/
Cloud deployment configurations organized by environment:
infrastructure/
├── kong/
│ ├── Dockerfile # Gateway image (generated, local and cloud)
│ ├── .dockerignore # Generated
│ └── dev/
│ └── kong.yml # Cloud gateway config for dev (generated, committed)
└── terraform/
└── dev/ # Development environment
├── main.tf
├── variables.tf
└── outputs.tf
Terraform files are generated per environment. See Infrastructure for details. The Kong files are generated by generate-kong (image) and infra:generate-kong (per-environment config); generate-kong also stages kong-plugins/ and declarative/ folders here, which are gitignored.
kong-plugins/
Optional. One folder per custom Kong plugin (handler.lua, schema.lua), built into the gateway image locally and in the cloud. Commit it. See Kong Plugins.
.tsdevstack/
Framework configuration directory:
.tsdevstack/
├── config.json # Main project configuration
├── config.schema.json # JSON schema for config validation
├── infrastructure.json # Infrastructure settings (tiers, domains, scaling)
├── infrastructure.schema.json # JSON schema for infrastructure validation
├── ci.json # CI/CD configuration
├── ci.schema.json # JSON schema for CI config
├── secret-map.json # Which secrets are assigned to which services
├── lint-staged-check.mjs # Pre-commit lint-staged configuration
└── .credentials.*.json # Cloud credentials (git-ignored)
This is where the framework stores its configuration. config.json contains your project name, services, and settings. infrastructure.json controls per-service scaling tiers, domains, and cloud-specific options. Schema files provide IDE auto-completion and validation.
Secrets files
Local development secrets are JSON files at the project root (all git-ignored):
.secrets.tsdevstack.json # Framework-generated secrets (do not edit)
.secrets.user.json # Your custom secrets (edit this one)
.secrets.local.json # Merged output (do not edit)
The three-file merge strategy ensures your customizations persist across framework updates. See Local Secrets for more.
Generated files
These files are created and managed by tsdevstack:
Do not edit generated files directly. Use override files instead:
kong.user.yml - Custom Kong routes (merged into kong.yml)
docker-compose.user.yml - Custom Docker config
.secrets.user.json - Your custom secrets
Configuration files
.tsdevstack/config.json
Framework configuration managed by CLI commands. This file is updated automatically when you add or remove services - you shouldn't need to edit it directly.
The exception is optional settings you set by hand, such as framework.apiKeys.ipLimitPerMinute (the per-IP ceiling on partner API routes, see API Keys).
npm workspaces
The monorepo uses npm workspaces with Lerna for task orchestration. Workspaces are defined in the root package.json:
{
"workspaces": [
"apps/*",
"packages/*"
]
}
Finding things