backend-scaffolding
Backend Scaffolding
Scaffold a Koa-based backend server with configuration, logging, routing with Zod validation, Mongoose models, and database connectivity.
Structure Overview
apps/backend/src/
├── config/
│ └── index.ts # Centralized configuration (env vars)
├── lib/
│ └── logger/
│ └── index.ts # Pino logger with pretty printing
├── models/
│ ├── _utils.ts # Model utilities (generateId, stripId)
│ ├── db.ts # MongoDB connection
│ └── {Model}.ts # Mongoose models
├── routes/
│ └── {resource}.ts # koa-zod-router routes
└── main.ts # Application entry point
Installation
npm install koa @koa/cors koa-bodyparser koa-mount koa-static koa-zod-router mongoose pino zod uuid
npm install -D @types/koa @types/koa__cors @types/koa-bodyparser @types/koa-mount @types/koa-static pino-pretty
For WebSocket support: npm install koa-websocket @types/koa-websocket
Implementation Steps
1. Config Module (config/index.ts)
Centralize all environment variables. Never use process.env directly outside this file.
const isDev = process.env.NODE_ENV !== 'production';
const config = {
isDev,
port: process.env.PORT || 3333,
mongo: {
database: process.env.MONGO_DATABASE || 'myapp',
protocol: process.env.MONGO_PROTOCOL || 'mongodb',
host: process.env.MONGO_HOST || 'localhost:27017',
username: process.env.MONGO_USERNAME || '',
password: process.env.MONGO_PASSWORD || '',
},
logging: {
level: process.env.LOG_LEVEL || (isDev ? 'debug' : 'info'),
routeLogging: process.env.ROUTE_LOGGING !== 'false',
},
};
export default config;
2. Logger Module (lib/logger/index.ts)
import pino from 'pino';
import config from '../../config';
export const logger = pino({
level: config.logging.level,
transport: config.isDev
? { target: 'pino-pretty', options: { colorize: true, translateTime: 'SYS:standard', ignore: 'pid,hostname' } }
: undefined,
});
export const createLogger = (name: string) => logger.child({ name });
export default logger;
3. Model Utilities (models/_utils.ts)
import { v4 as uuidv4 } from 'uuid';
export const generateId = (): string => uuidv4();
export const stripId = (_doc: unknown, ret: Record<string, unknown>) => {
delete ret._id;
return ret;
};
4. Database Connection (models/db.ts)
import mongoose from 'mongoose';
import config from '../config';
import { createLogger } from '../lib/logger';
const log = createLogger('db');
export async function init() {
const user = config.mongo.username && config.mongo.password
? `${encodeURIComponent(config.mongo.username)}:${encodeURIComponent(config.mongo.password)}@`
: '';
const connectionString = `${config.mongo.protocol}://${user}${config.mongo.host}/${config.mongo.database}`;
await mongoose.connect(connectionString);
log.info({ database: config.mongo.database }, 'Connected to MongoDB');
}
5. Models, Routes, and Main Entry Point
See references/examples.md for complete code examples including:
- Example Mongoose model with proper typing
- Example routes with Zod validation (CRUD operations)
- Main entry point with middleware setup
- Shared types definition
Environment Variables
PORT=3333
NODE_ENV=development
MONGO_DATABASE=myapp
MONGO_PROTOCOL=mongodb
MONGO_HOST=localhost:27017
MONGO_USERNAME=
MONGO_PASSWORD=
LOG_LEVEL=debug
ROUTE_LOGGING=true
Checklist
- Install dependencies:
npm install - Start MongoDB:
docker compose up -dor local MongoDB - Set environment: Copy
.env.exampleto.env.local, rundirenv allow - Start backend:
just serve-backend - Test health:
curl http://localhost:3333/api - Test CRUD: See examples in references/examples.md
Best Practices
- Config: Always use
configobject, neverprocess.envdirectly - Logging: Use
createLogger('module-name'), neverconsole.log - Routes: Use
koa-zod-routerwith Zod schemas for validation - Models: Use
generateId()for IDs,stripIdtransform for JSON output - Types: Define shared types in
libs/types, import via@{project}/types - Errors: Return structured error responses with appropriate status codes
More from workshop-ventures/skills
frontend-scaffolding
Scaffold a React frontend with Tailwind CSS, React Router, React Query, and standard project structure. Use when asked to "create a frontend", "scaffold webapp", "set up React app", or "initialize frontend structure".
16new-project-scaffolding
Scaffold a new Nx monorepo project with backend, frontend, shared types library, justfile commands, and direnv setup. Use when starting a fresh project or asked to "create a new project", "scaffold a monorepo", or "set up a new workspace".
11backend-metrics
Add OpenTelemetry metrics and observability to the backend. Use when asked to "add metrics", "add observability", "track requests", or "add OpenTelemetry".
10frontend-hooks-creation
Create React Query hooks for API endpoints with proper typing and cache invalidation. Use when asked to "create hooks", "add frontend hooks", "create API hooks", or "add React Query hooks".
9backend-ai-tools
Create AI tools for use with Vercel AI SDK agents. Use when asked to "create AI tools", "add agent tools", "create tool for AI", or "add tools to agent".
8backend-ai-agent
Create AI agents using Vercel AI SDK with tool use, tracing, and failover. Use when asked to "create an AI agent", "add AI", "create LLM integration", or "build an assistant".
8