Core Node.js backend patterns for TypeScript applications including async/await error handling, middleware concepts, configuration management, testing strategies, and layered architecture principles. Use when building Node.js backend services, APIs, or microservices.
From hugin-v0npx claudepluginhub michelve/hugin-marketplace --plugin hugin-v0This skill uses the workspace's default tool permissions.
resources/architecture-patterns.mdresources/async-and-errors.mdresources/testing-guide.mdGuides browser automation with Playwright, Puppeteer, Selenium for e2e testing and scraping. Teaches reliable selectors, auto-waits, isolation to fix flaky tests.
Provides checklists to review code for functionality, quality, security, performance, tests, and maintainability. Use for PRs, audits, team standards, and developer training.
Enforces A/B test setup with gates for hypothesis locking, metrics definition, sample size calculation, assumptions checks, and execution readiness before implementation.
!`cat package.json 2>/dev/null || echo '{"error": "No package.json found."}'`
Core patterns for building scalable Node.js backend applications with TypeScript, emphasizing clean architecture, error handling, and testability.
src/
├── api/
│ ├── routes/ # HTTP route definitions
│ ├── controllers/ # Request/response handling
│ ├── services/ # Business logic
│ └── repositories/ # Data access
├── middleware/ # Express middleware
├── types/ # TypeScript types
├── config/ # Configuration
└── utils/ # Utilities
Flow: Route → Controller → Service → Repository → Database
See resources/async-and-errors.md for async/await patterns (basic pattern, controller pattern, Promise.all for parallel operations, custom error classes, async error wrapper).
// Request body
interface CreateUserRequest {
email: string;
name: string;
password: string;
}
// Response
interface ApiResponse<T> {
success: boolean;
data?: T;
error?: string;
message?: string;
}
// Usage
async function createUser(
req: Request<{}, {}, CreateUserRequest>,
res: Response<ApiResponse<User>>,
): Promise<void> {
const { email, name, password } = req.body;
const user = await userService.create({ email, name, password });
res.json({
success: true,
data: user,
});
}
interface IUserService {
getById(id: string): Promise<User>;
create(data: CreateUserDto): Promise<User>;
update(id: string, data: UpdateUserDto): Promise<User>;
delete(id: string): Promise<void>;
}
class UserService implements IUserService {
async getById(id: string): Promise<User> {
// Implementation
}
async create(data: CreateUserDto): Promise<User> {
// Implementation
}
async update(id: string, data: UpdateUserDto): Promise<User> {
// Implementation
}
async delete(id: string): Promise<void> {
// Implementation
}
}
// config/env.ts
import { z } from "zod";
const envSchema = z.object({
NODE_ENV: z.enum(["development", "production", "test"]),
PORT: z.string().transform(Number),
DATABASE_URL: z.string().url(),
JWT_SECRET: z.string().min(32),
LOG_LEVEL: z.enum(["error", "warn", "info", "debug"]).default("info"),
});
export const env = envSchema.parse(process.env);
// config/index.ts
interface Config {
server: {
port: number;
host: string;
};
database: {
url: string;
};
auth: {
jwtSecret: string;
jwtExpiry: string;
};
}
export const config: Config = {
server: {
port: parseInt(process.env.PORT || "3000"),
host: process.env.HOST || "localhost",
},
database: {
url: process.env.DATABASE_URL || "",
},
auth: {
jwtSecret: process.env.JWT_SECRET || "",
jwtExpiry: process.env.JWT_EXPIRY || "7d",
},
};
See resources/architecture-patterns.md for detailed controller, service, and repository layer implementations plus dependency injection patterns.
See resources/async-and-errors.md for custom error classes (AppError, NotFoundError, ValidationError) and async error wrapper pattern.
// ✅ Good: async/await
async function getUser(id: string): Promise<User> {
const user = await userRepository.findById(id);
return user;
}
// ❌ Avoid: Promise chains
function getUser(id: string): Promise<User> {
return userRepository.findById(id)
.then(user => user)
.catch(error => throw error);
}
// ✅ Good: Separated layers
// Controller handles HTTP
// Service handles business logic
// Repository handles data access
// ❌ Avoid: Business logic in controllers
class UserController {
async create(req: Request, res: Response) {
// ❌ Don't put business logic here
const hashedPassword = await hash(req.body.password);
const user = await db.user.create({...});
res.json(user);
}
}
// ✅ Good: Full type coverage
async function updateUser(id: string, data: UpdateUserDto): Promise<User> {
return userService.update(id, data);
}
// ❌ Avoid: any types
async function updateUser(id: any, data: any): Promise<any> {
return userService.update(id, data);
}
For more patterns, see: