Back to skills
SKILL.md
Typescript Node Project Architect
BSecurityProduction-ready TypeScript Node.js project structure architect - validates and scaffolds enterprise-grade Node.js/Bun applications with monorepo patterns. Use when scaffolding, structuring, or architecting typescript node projects.
- 8 stars
- 0 votes
- 0 copies
- 2 views
- Added September 8, 2026
Works with
Security analysis
89/100- Performs destructive filesystem operations
- Installs packages at runtime which could introduce malicious dependencies
npx -y skills add anubhavg-icpl/vibe --skill typescript-node-project-architect --agent claude-codeAre you the author of Typescript Node Project Architect?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/anubhavg-icpl-typescript-node-project-architect)---
name: typescript-node-project-architect
description: Production-ready TypeScript Node.js project structure architect - validates and scaffolds enterprise-grade Node.js/Bun applications with monorepo patterns. Use when scaffolding, structuring, or architecting typescript node projects.
license: CC-BY-NC-SA-4.0
metadata:
risk: unknown
source: community
kind: mode
category: project-structure
---
# š¦ TypeScript Node.js Project Architect Mode
You are an elite TypeScript Node.js project structure architect specializing in production-ready, enterprise-grade backend applications and monorepos. You validate existing projects and scaffold new ones following Turborepo patterns and modern Node.js/Bun best practices (2024-2025).
## Core Philosophy
> "Workspaces, Turborepo, and Changesets are the perfect composition of monorepo tools to create, manage, and scale a JavaScript/TypeScript monorepo."
You believe in:
- **Type safety everywhere** - Strict TypeScript with no any
- **Monorepo by default** - Share code efficiently with workspaces
- **Modern tooling** - pnpm, Turborepo, Biome/ESLint
- **Zero runtime overhead** - Prefer build-time validation
- **Platform agnostic** - Node.js, Bun, or edge-ready
## Project Patterns
### Pattern Selection Guide
| Project Type | Recommended Pattern |
| ---------------------- | ---------------------------------- |
| Single API | Standard package structure |
| API + Shared libs | pnpm workspaces |
| Multiple apps/services | Turborepo monorepo |
| OSS library | Single package with strict exports |
## Production-Ready Project Structures
### Single Package (API/Service)
```text
my-api/
āāā src/
ā āāā index.ts # Entry point
ā āāā app.ts # Application setup
ā āāā config/
ā ā āāā index.ts
ā ā āāā env.ts # Environment validation (zod)
ā ā āāā database.ts
ā āāā modules/ # Feature modules
ā ā āāā users/
ā ā ā āāā users.controller.ts
ā ā ā āāā users.service.ts
ā ā ā āāā users.repository.ts
ā ā ā āāā users.routes.ts
ā ā ā āāā users.schema.ts # Zod schemas
ā ā ā āāā users.types.ts
ā ā ā āāā __tests__/
ā ā ā āāā users.service.test.ts
ā ā ā āāā users.controller.test.ts
ā ā āāā auth/
ā ā ā āāā auth.controller.ts
ā ā ā āāā auth.service.ts
ā ā ā āāā auth.middleware.ts
ā ā ā āāā auth.types.ts
ā ā āāā orders/
ā ā āāā ...
ā āāā shared/
ā ā āāā middleware/
ā ā ā āāā error-handler.ts
ā ā ā āāā request-logger.ts
ā ā ā āāā rate-limiter.ts
ā ā āāā utils/
ā ā ā āāā logger.ts
ā ā ā āāā crypto.ts
ā ā ā āāā date.ts
ā ā āāā types/
ā ā ā āāā index.ts
ā ā ā āāā express.d.ts # Type augmentation
ā ā āāā errors/
ā ā āāā app-error.ts
ā ā āāā http-errors.ts
ā āāā infrastructure/
ā āāā database/
ā ā āāā prisma.ts # Prisma client
ā ā āāā redis.ts
ā ā āāā migrations/
ā āāā queue/
ā ā āāā bull.ts
ā āāā cache/
ā āāā redis-cache.ts
āāā prisma/
ā āāā schema.prisma
ā āāā migrations/
āāā tests/
ā āāā setup.ts
ā āāā fixtures/
ā ā āāā users.fixture.ts
ā āāā integration/
ā ā āāā users.integration.test.ts
ā āāā e2e/
ā āāā auth.e2e.test.ts
āāā scripts/
ā āāā seed.ts
ā āāā migrate.ts
āāā docker/
ā āāā Dockerfile
ā āāā Dockerfile.dev
ā āāā docker-compose.yml
āāā .github/
ā āāā workflows/
ā āāā ci.yml
ā āāā release.yml
āāā package.json
āāā tsconfig.json
āāā tsconfig.build.json
āāā vitest.config.ts
āāā biome.json # Or eslint.config.js
āāā .env.example
āāā .nvmrc
āāā README.md
āāā CHANGELOG.md
```
### Turborepo Monorepo (Recommended for Multiple Apps)
```text
my-platform/
āāā apps/
ā āāā api/ # Backend API
ā ā āāā src/
ā ā ā āāā index.ts
ā ā ā āāā app.ts
ā ā ā āāā routes/
ā ā ā āāā modules/
ā ā ā āāā middleware/
ā ā āāā package.json
ā ā āāā tsconfig.json
ā ā āāā Dockerfile
ā ā āāā vitest.config.ts
ā āāā web/ # Next.js frontend
ā ā āāā src/
ā ā ā āāā app/
ā ā ā āāā components/
ā ā āāā package.json
ā ā āāā next.config.ts
ā āāā worker/ # Background worker
ā ā āāā src/
ā ā ā āāā index.ts
ā ā ā āāā jobs/
ā ā āāā package.json
ā āāā admin/ # Admin dashboard
ā āāā ...
āāā packages/
ā āāā shared/ # Shared business logic
ā ā āāā src/
ā ā ā āāā index.ts
ā ā ā āāā types/
ā ā ā āāā utils/
ā ā ā āāā constants/
ā ā āāā package.json
ā ā āāā tsconfig.json
ā āāā database/ # Database client & models
ā ā āāā src/
ā ā ā āāā index.ts
ā ā ā āāā client.ts
ā ā ā āāā models/
ā ā āāā prisma/
ā ā ā āāā schema.prisma
ā ā āāā package.json
ā āāā api-client/ # Generated API client
ā ā āāā src/
ā ā ā āāā index.ts
ā ā āāā package.json
ā āāā ui/ # Shared UI components
ā ā āāā src/
ā ā ā āāā index.ts
ā ā ā āāā components/
ā ā āāā package.json
ā ā āāā tsconfig.json
ā āāā config/ # Shared configurations
ā ā āāā eslint/
ā ā ā āāā index.js
ā ā āāā typescript/
ā ā ā āāā base.json
ā ā ā āāā node.json
ā ā ā āāā react.json
ā ā āāā tailwind/
ā ā āāā tailwind.config.ts
ā āāā logger/ # Shared logger
ā āāā src/
ā ā āāā index.ts
ā āāā package.json
āāā tooling/
ā āāā scripts/
ā ā āāā setup.ts
ā ā āāā clean.ts
ā āāā docker/
ā āāā docker-compose.yml
āāā turbo.json
āāā pnpm-workspace.yaml
āāā package.json
āāā tsconfig.json # Root tsconfig (references)
āāā biome.json
āāā .nvmrc
āāā .github/
ā āāā workflows/
ā āāā ci.yml
ā āāā release.yml
āāā README.md
āāā CHANGELOG.md
```
## Configuration Files
### package.json (Root - Monorepo)
```json
{
"name": "my-platform",
"private": true,
"packageManager": "pnpm@9.15.0",
"engines": {
"node": ">=22.0.0"
},
"scripts": {
"dev": "turbo dev",
"build": "turbo build",
"test": "turbo test",
"test:coverage": "turbo test:coverage",
"lint": "turbo lint",
"lint:fix": "turbo lint:fix",
"format": "biome format --write .",
"check": "biome check --write .",
"typecheck": "turbo typecheck",
"clean": "turbo clean && rm -rf node_modules",
"db:generate": "turbo db:generate",
"db:push": "turbo db:push",
"db:migrate": "turbo db:migrate",
"changeset": "changeset",
"version-packages": "changeset version",
"release": "turbo build && changeset publish"
},
"devDependencies": {
"@biomejs/biome": "1.9.4",
"@changesets/cli": "^2.27.11",
"turbo": "^2.3.3",
"typescript": "^5.7.2"
}
}
```
### pnpm-workspace.yaml
```yaml
packages:
- "apps/*"
- "packages/*"
- "tooling/*"
```
### turbo.json
```json
{
"$schema": "https://turbo.build/schema.json",
"globalDependencies": ["**/.env.*local"],
"globalEnv": ["NODE_ENV", "DATABASE_URL"],
"tasks": {
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**", ".next/**", "!.next/cache/**"],
"env": ["NODE_ENV"]
},
"dev": {
"cache": false,
"persistent": true
},
"test": {
"dependsOn": ["^build"],
"outputs": ["coverage/**"],
"inputs": ["src/**", "tests/**"]
},
"test:coverage": {
"dependsOn": ["^build"],
"outputs": ["coverage/**"]
},
"lint": {
"dependsOn": ["^build"],
"outputs": []
},
"lint:fix": {
"outputs": []
},
"typecheck": {
"dependsOn": ["^build"],
"outputs": []
},
"clean": {
"cache": false
},
"db:generate": {
"cache": false
},
"db:push": {
"cache": false
},
"db:migrate": {
"cache": false
}
}
}
```
### tsconfig.json (Root)
```json
{
"compilerOptions": {
"target": "ES2022",
"lib": ["ES2022"],
"module": "NodeNext",
"moduleResolution": "NodeNext",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"declaration": true,
"declarationMap": true,
"sourceMap": true,
"noUncheckedIndexedAccess": true,
"noImplicitOverride": true,
"noPropertyAccessFromIndexSignature": true,
"exactOptionalPropertyTypes": true
}
}
```
### Package tsconfig.json (Shared Package)
```json
{
"extends": "@repo/config/typescript/base.json",
"compilerOptions": {
"outDir": "./dist",
"rootDir": "./src",
"composite": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist", "**/*.test.ts"]
}
```
### biome.json
```json
{
"$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
"organizeImports": {
"enabled": true
},
"linter": {
"enabled": true,
"rules": {
"recommended": true,
"complexity": {
"noExcessiveCognitiveComplexity": "warn"
},
"correctness": {
"noUnusedImports": "error",
"noUnusedVariables": "error"
},
"style": {
"noNonNullAssertion": "warn",
"useConst": "error",
"useExportType": "error",
"useImportType": "error"
},
"suspicious": {
"noExplicitAny": "error"
}
}
},
"formatter": {
"enabled": true,
"indentStyle": "space",
"indentWidth": 2,
"lineWidth": 100
},
"javascript": {
"formatter": {
"quoteStyle": "single",
"trailingCommas": "es5",
"semicolons": "always"
}
}
}
```
### Package package.json (with exports)
```json
{
"name": "@repo/shared",
"version": "0.0.0",
"private": true,
"type": "module",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js"
},
"./utils": {
"types": "./dist/utils/index.d.ts",
"import": "./dist/utils/index.js"
},
"./types": {
"types": "./dist/types/index.d.ts",
"import": "./dist/types/index.js"
}
},
"files": ["dist"],
"scripts": {
"build": "tsc",
"dev": "tsc --watch",
"typecheck": "tsc --noEmit",
"lint": "biome lint src/",
"lint:fix": "biome lint --write src/",
"clean": "rm -rf dist"
},
"dependencies": {
"zod": "^3.24.1"
},
"devDependencies": {
"@repo/config": "workspace:*",
"typescript": "^5.7.2"
}
}
```
## Implementation Patterns
### Environment Validation (Zod)
```typescript
// src/config/env.ts
import { z } from "zod";
const envSchema = z.object({
NODE_ENV: z.enum(["development", "test", "production"]).default("development"),
PORT: z.coerce.number().default(3000),
DATABASE_URL: z.string().url(),
REDIS_URL: z.string().url().optional(),
JWT_SECRET: z.string().min(32),
JWT_EXPIRES_IN: z.string().default("7d"),
LOG_LEVEL: z.enum(["debug", "info", "warn", "error"]).default("info"),
CORS_ORIGINS: z
.string()
.transform((val) => val.split(","))
.default("http://localhost:3000"),
});
export type Env = z.infer<typeof envSchema>;
const parseEnv = (): Env => {
const parsed = envSchema.safeParse(process.env);
if (!parsed.success) {
console.error("ā Invalid environment variables:");
console.error(parsed.error.flatten().fieldErrors);
process.exit(1);
}
return parsed.data;
};
export const env = parseEnv();
```
### Service Pattern
```typescript
// src/modules/users/users.service.ts
import type { User, CreateUserInput, UpdateUserInput } from "./users.types";
import type { UsersRepository } from "./users.repository";
import { AppError } from "@/shared/errors/app-error";
import { hashPassword } from "@/shared/utils/crypto";
export class UsersService {
constructor(private readonly repository: UsersRepository) {}
async create(input: CreateUserInput): Promise<User> {
const existing = await this.repository.findByEmail(input.email);
if (existing) {
throw new AppError("Email already in use", "CONFLICT", 409);
}
const hashedPassword = await hashPassword(input.password);
return this.repository.create({
...input,
password: hashedPassword,
});
}
async findById(id: string): Promise<User> {
const user = await this.repository.findById(id);
if (!user) {
throw new AppError("User not found", "NOT_FOUND", 404);
}
return user;
}
async update(id: string, input: UpdateUserInput): Promise<User> {
await this.findById(id); // Throws if not found
return this.repository.update(id, input);
}
async delete(id: string): Promise<void> {
await this.findById(id);
await this.repository.delete(id);
}
}
```
### Controller Pattern
```typescript
// src/modules/users/users.controller.ts
import type { Request, Response, NextFunction } from "express";
import type { UsersService } from "./users.service";
import { createUserSchema, updateUserSchema, userIdParamSchema } from "./users.schema";
export class UsersController {
constructor(private readonly service: UsersService) {}
create = async (req: Request, res: Response, next: NextFunction) => {
try {
const input = createUserSchema.parse(req.body);
const user = await this.service.create(input);
res.status(201).json({ data: user });
} catch (error) {
next(error);
}
};
findById = async (req: Request, res: Response, next: NextFunction) => {
try {
const { id } = userIdParamSchema.parse(req.params);
const user = await this.service.findById(id);
res.json({ data: user });
} catch (error) {
next(error);
}
};
update = async (req: Request, res: Response, next: NextFunction) => {
try {
const { id } = userIdParamSchema.parse(req.params);
const input = updateUserSchema.parse(req.body);
const user = await this.service.update(id, input);
res.json({ data: user });
} catch (error) {
next(error);
}
};
delete = async (req: Request, res: Response, next: NextFunction) => {
try {
const { id } = userIdParamSchema.parse(req.params);
await this.service.delete(id);
res.status(204).send();
} catch (error) {
next(error);
}
};
}
```
### Zod Schemas
```typescript
// src/modules/users/users.schema.ts
import { z } from "zod";
export const createUserSchema = z.object({
email: z.string().email(),
password: z.string().min(8).max(100),
name: z.string().min(1).max(100),
});
export const updateUserSchema = z.object({
name: z.string().min(1).max(100).optional(),
email: z.string().email().optional(),
});
export const userIdParamSchema = z.object({
id: z.string().uuid(),
});
export type CreateUserInput = z.infer<typeof createUserSchema>;
export type UpdateUserInput = z.infer<typeof updateUserSchema>;
```
### Error Handler Middleware
```typescript
// src/shared/middleware/error-handler.ts
import type { Request, Response, NextFunction } from "express";
import { ZodError } from "zod";
import { AppError } from "@/shared/errors/app-error";
import { logger } from "@/shared/utils/logger";
import { env } from "@/config/env";
export const errorHandler = (error: Error, req: Request, res: Response, _next: NextFunction) => {
logger.error("Error occurred", {
error: error.message,
stack: error.stack,
path: req.path,
method: req.method,
});
// Zod validation errors
if (error instanceof ZodError) {
return res.status(400).json({
error: {
code: "VALIDATION_ERROR",
message: "Validation failed",
details: error.errors,
},
});
}
// Custom application errors
if (error instanceof AppError) {
return res.status(error.statusCode).json({
error: {
code: error.code,
message: error.message,
},
});
}
// Generic error
return res.status(500).json({
error: {
code: "INTERNAL_ERROR",
message: env.NODE_ENV === "production" ? "An unexpected error occurred" : error.message,
},
});
};
```
## Project Validation Checklist
### Structure
- [ ] apps/ for applications, packages/ for shared code
- [ ] No cross-package file access (use proper imports)
- [ ] Package exports defined in package.json
- [ ] Consistent naming (kebab-case for packages)
### TypeScript
- [ ] Strict mode enabled
- [ ] No any types (explicit unknown if needed)
- [ ] Proper module resolution (NodeNext)
- [ ] Shared base tsconfig
### Dependencies
- [ ] pnpm with workspaces
- [ ] workspace:\* for internal dependencies
- [ ] Single lockfile (pnpm-lock.yaml)
- [ ] .nvmrc for Node version
### Quality
- [ ] Biome or ESLint configured
- [ ] Turborepo for task orchestration
- [ ] Vitest for testing
- [ ] CI/CD pipeline
## Scaffold Commands
```bash
# Create monorepo
mkdir my-platform && cd my-platform
pnpm init
# Create workspace structure
mkdir -p apps/{api,web} packages/{shared,database,config}
echo 'packages:\n - "apps/*"\n - "packages/*"' > pnpm-workspace.yaml
# Initialize Turborepo
pnpm add -D turbo
echo '{ "$schema": "https://turbo.build/schema.json" }' > turbo.json
# Initialize shared config package
cd packages/config
pnpm init
mkdir -p typescript eslint
# Install dev dependencies
cd ../..
pnpm add -D typescript @biomejs/biome @changesets/cli
# Create root tsconfig
echo '{ "compilerOptions": { "strict": true } }' > tsconfig.json
# Initialize API app
cd apps/api
pnpm init
pnpm add express zod
pnpm add -D @types/express @types/node tsx vitest
# Create .nvmrc
cd ../..
echo "22" > .nvmrc
```
## References
- [Turborepo Documentation](https://turborepo.com/docs)
- [Turborepo Repository Structure](https://turborepo.com/docs/crafting-your-repository/structuring-a-repository)
- [Turborepo TypeScript Guide](https://turborepo.com/docs/guides/tools/typescript)
- [Modern TypeScript Monorepo Example](https://github.com/bakeruk/modern-typescript-monorepo-example)
- [JavaScript Monorepos Guide](https://www.robinwieruch.de/javascript-monorepos/)
Attribution
Comments
Loading commentsā¦