plugins/backend/skills/express/SKILL.md
Expert skill for Express.js web framework development across Express 4.x and 5.x. Covers middleware chain, routing, error handling, request/response lifecycle, template engines, security (Helmet, CORS), body parsing, TypeScript setup, testing, and deployment. WHEN: "Express", "express.js", "express middleware", "app.use", "app.get", "app.post", "express router", "middleware ordering", "express error handler", "req.params", "req.query", "req.body", "res.json", "res.send", "express-validator", "supertest", "helmet", "cors middleware", "express rate limit", "multer", "express-session", "passport express", "Express 5", "express TypeScript". Do NOT use for general Node.js scripting, automation, or CLI-tool questions unrelated to the Express framework — that's the `cli-scripting` plugin's `nodejs` skill.
npx skillsauth add chrishuffman5/domain-expert expressInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
This skill covers Express.js web framework development across Express 4.x and 5.x. Express is a minimal, unopinionated Node.js web framework providing a thin layer of fundamental web application features: routing, middleware composition, and HTTP utilities. Its power comes from composing third-party middleware into a pipeline.
Classify the request:
references/architecture.md for middleware internals, routing engine, request/response lifecycle, Express 5 breaking changes, error handling patternsreferences/best-practices.md for project structure, security (helmet, cors, rate-limit), testing (supertest), deployment (cluster, PM2, Docker), performance tuning, popular middleware integrationreferences/diagnostics.md for common errors (middleware ordering, unhandled rejections, CORS misconfig, body parsing), debugging, memory leaks, async error handlingreferences/versions/5.x.md for path-to-regexp v8, removed deprecated methods, promise rejection handling, migration from Express 4Identify version -- Determine whether the project targets Express 4.x or 5.x from package.json, import style, or explicit mention. Default to Express 5 for new projects.
Load context -- Read the relevant reference file before answering.
Analyze -- Apply Express-specific reasoning. Consider middleware ordering, the (req, res, next) contract, error handler signature requirements, and the sync/async distinction between Express 4 and 5.
Recommend -- Provide concrete JavaScript or TypeScript code examples with explanations. Always qualify trade-offs.
Verify -- Suggest validation steps: running tests with supertest, checking middleware order, verifying error handler registration.
Every Express application is a pipeline of middleware functions. Each function receives (req, res, next) and must either terminate the response or call next().
const app = express();
// Middleware executes in registration order
app.use(helmet()); // 1. Security headers
app.use(cors(corsOptions)); // 2. CORS
app.use(rateLimit({ windowMs: 15*60*1000, max: 100 })); // 3. Rate limiting
app.use(morgan('combined')); // 4. Logging
app.use(compression()); // 5. Compression
app.use(express.json({ limit: '10mb' })); // 6. Body parsing
app.use(express.urlencoded({ extended: true }));
app.use('/api/v1', apiRouter); // 7. Routes
app.use(notFoundHandler); // 8. 404 -- after all routes
app.use(errorHandler); // 9. Error handler -- always last
Critical rules:
(err, req, res, next) -- 4 arguments) always lastError-handling middleware is distinguished solely by its 4-parameter signature. Express checks function.length to identify it.
// Error handler -- must have exactly 4 params
app.use((err, req, res, next) => {
if (res.headersSent) return next(err);
const status = err.status ?? err.statusCode ?? 500;
res.status(status).json({
error: { message: err.message, code: err.code ?? 'INTERNAL_ERROR' },
});
});
Express 5: Async errors in route handlers are automatically forwarded to error middleware -- no try/catch or asyncHandler wrapper needed.
Express 4: Requires explicit next(err) calls or wrapper libraries like express-async-errors.
Express Router creates modular, mountable route handlers:
const router = express.Router();
router.use(authenticate);
router.get('/', listUsers);
router.post('/', validate(schema), createUser);
router.route('/:id')
.get(getUser)
.put(validate(schema), updateUser)
.delete(authorize('admin'), deleteUser);
app.use('/api/v1/users', router);
// Request properties
req.params // URL segments (:id)
req.query // Query string (?page=1)
req.body // Parsed body (requires body-parsing middleware)
req.headers // HTTP headers
req.ip // Client IP (respects trust proxy)
req.hostname // Host without port
req.path // URL pathname
// Response methods
res.json(data) // Send JSON
res.status(201).json(data) // Status + JSON
res.send(data) // Auto-detect content type
res.redirect(301, url) // Redirect
res.sendFile(absolutePath) // Serve file
res.cookie(name, val, opts) // Set cookie
// src/types/express.d.ts -- augment Request
declare global {
namespace Express {
interface Request {
user?: User;
requestId: string;
}
}
}
export {};
// tsconfig.json essentials
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"strict": true,
"esModuleInterop": true
}
}
Development: tsx watch src/server.ts. Build: tsc. Production: node dist/server.js.
// app.ts -- no listen()
export function createApp(): Application {
const app = express();
app.use(helmet());
app.use(cors());
app.use(express.json());
app.use('/api/v1/users', usersRouter);
app.use(notFoundHandler);
app.use(errorHandler);
return app;
}
// server.ts -- starts listening
const app = createApp();
app.listen(config.PORT);
class AppError extends Error {
constructor(
message: string,
public status: number = 500,
public code?: string,
public isOperational: boolean = true,
) {
super(message);
}
}
class NotFoundError extends AppError {
constructor(resource = 'Resource') {
super(`${resource} not found`, 404, 'NOT_FOUND');
}
}
const validateBody = (schema: ZodSchema) => (req, res, next) => {
const result = schema.safeParse(req.body);
if (!result.success) {
return res.status(422).json({ errors: result.error.issues });
}
req.validatedBody = result.data;
next();
};
// Behind a reverse proxy (Nginx, ALB) -- required for correct req.ip, req.protocol
app.set('trust proxy', 1); // trust first hop
app.set('trust proxy', 'loopback'); // trust loopback
Express supports Pug, EJS, and Handlebars via app.set('view engine', 'pug'). For API-only services, skip template engines entirely. For SSR, consider Next.js or Remix before raw Express templating.
| Feature | Express 4 | Express 5 |
|---|---|---|
| Async error handling | Manual next(err) required | Automatic -- rejections forwarded |
| Wildcard routes | * allowed | Named wildcard :name* required |
| Path syntax | Loose (path-to-regexp v0) | Strict (path-to-regexp v8) |
| req.param() | Deprecated but available | Removed |
| res.send(status, body) | Deprecated but works | Removed |
| Node.js minimum | Node 10+ | Node 18+ |
| Bun/Deno support | Partial | Full |
| Version | Status | Reference | What's version-specific |
|---|---|---|---|
| Express 5.x | Stable (2024+) | references/versions/5.x.md | path-to-regexp v8, auto async errors, removed deprecated APIs, Bun/Deno compat |
| Express 4.x | Maintenance | (none -- covered directly above) | Legacy, manual async error handling, loose path syntax |
Default to Express 5 for all new projects. Express 4 guidance is for migration and legacy support.
| Dimension | Express 5 | Fastify 5 | Koa 2 |
|---|---|---|---|
| Throughput | ~45k req/s | ~75k req/s | ~50k req/s |
| Middleware | (req, res, next) | Hooks + plugins | (ctx, next) async |
| Async errors | Auto (v5) | Native | Native |
| Schema validation | Manual (zod, joi) | Built-in (ajv) | Manual |
| Ecosystem | Largest | Large, growing | Moderate |
| Learning curve | Lowest | Moderate | Low |
Choose Express when: maximum ecosystem compatibility, team expertise, existing codebase, middleware selection matters more than raw throughput.
Consider Fastify when: throughput is critical, built-in validation/serialization is valued, TypeScript-first with generics.
app.use(helmet()) -- sets CSP, HSTS, X-Frame-Options, X-Content-Type-OptionsmaxAgeexpress-rate-limit on auth endpoints and API routesexpress-validator or Zod middleware before handlersexpress.json({ limit: '10mb' }) to prevent payload abusehttpOnly, secure, sameSite: 'strict'Load these for deep knowledge on specific topics:
references/architecture.md -- Middleware internals, routing engine, request/response lifecycle, Express 5 breaking changes, error handling patterns. Load when: architecture questions, middleware ordering, Express 5 migration, routing issues.references/best-practices.md -- Project structure, security (helmet, cors, rate-limit), testing (supertest), deployment (cluster, PM2, Docker), performance, popular middleware integration (passport, multer, express-validator). Load when: "how should I structure", security review, testing setup, deployment patterns.references/diagnostics.md -- Common errors (middleware ordering, unhandled rejections, CORS, body parsing), debugging, memory leaks, async error handling. Load when: troubleshooting errors, debugging issues, diagnosing performance problems.Ready-made npm/node audit (read-only) in scripts/.
scripts/01-dependency-and-security-audit.sh -- npm vulns, outdated deps, security-middleware presencetools
kubectl command-line usage and scripting: kubeconfig and context management, output formats (jsonpath, custom-columns, go-template), all major verbs (get, describe, apply, delete, exec, logs, port-forward, rollout, scale, drain), workload resources, config/storage, networking, RBAC, node management, debugging (CrashLoopBackOff, ImagePullBackOff, OOMKilled), and scripting patterns (dry-run, diff, wait, jq, kustomize). WHEN: "kubectl", "k8s CLI", "kubeconfig", "namespace", "pod", "deployment", "service", "ingress", "configmap", "secret", "rollout", "scale", "drain", "taint", "kustomize". Do NOT use for cluster architecture, sizing, upgrades, or workload design decisions — that's the `kubernetes` skill in the `containers` plugin. This skill is command syntax and scripting kubectl against an existing cluster, not cluster ops.
tools
Bash 5.x shell scripting, Unix text processing, and command-line automation: variables, parameter expansion, quoting, control flow, functions, I/O redirection, error handling (set -euo pipefail, trap), and the Unix tool ecosystem (grep, sed, awk, jq, find, sort, uniq, cut, xargs). Covers process management, networking (curl, ssh, rsync, nc), file locking (flock), parallel execution, and production script patterns. WHEN: "Bash", "bash", "shell", "sh", ".sh", "shell script", "sed", "awk", "grep", "jq", "find", "xargs", "curl", "ssh", "rsync", "cron", "pipe", "redirect", "here-doc", "shebang", "POSIX", "set -euo pipefail", "trap".
tools
Azure CLI (az) command syntax and scripting: authentication (interactive, service principal, managed identity, SSO), output formats and JMESPath queries, resource groups, VMs, storage accounts/blobs, networking (VNets, NSGs, load balancers, DNS), Entra ID, AKS, App Service, Functions, databases (SQL, Cosmos DB, MySQL, PostgreSQL), Key Vault, Monitor/alerting, and infrastructure scripting patterns. WHEN: "az ", "Azure CLI", "az login", "az vm", "az aks", "az storage", "az keyvault", "az monitor", "az ad", "az group", "az network", "az webapp", "az functionapp", "az sql", "az cosmosdb", "JMESPath", "az account". Do NOT use for Azure architecture, landing zones, or multi-subscription strategy — that's the `cloud-platforms` plugin. This skill is about command syntax and scripting the CLI, not deciding what to provision.
tools
AWS CLI v2 command syntax and scripting: authentication (profiles, SSO, assume-role, instance profiles), output formats and JMESPath queries, pagination and waiters, IAM, S3, Lambda, RDS, CloudFormation, ECS, EKS, CloudWatch, SSM, Route 53, STS, and VPC networking. WHEN: "aws ", "AWS CLI", "aws ec2", "aws s3", "aws lambda", "aws iam", "aws cloudformation", "aws ssm", "aws ecs", "aws eks", "aws rds", "aws cloudwatch", "aws route53", "aws sts". Do NOT use for AWS architecture, service selection, multi-account strategy, or FinOps — that's the `cloud-platforms` plugin. This skill is about command syntax and scripting the CLI, not deciding what to provision.