Backend Development
Use this skill for backend work in a Next.js app. Favor reusable, testable server code with explicit boundaries and security review built into the workflow.
Architecture Rules
- Keep reusable backend code under the
/serverroot folder. - Treat Next.js API routes and server-action entrypoints as the thin edge. They should parse framework inputs, call controllers, and return framework responses.
- Keep route handlers in
app/api/**/route.jsorapp/api/**/route.tslean; all reusable validation, orchestration, business logic, persistence, and security helpers should live under/server. - Put request orchestration in controllers. Controllers validate inputs, call services, map errors, and shape responses.
- Put business logic in services. Services coordinate use cases and should not depend on Next.js request/response objects.
- Put persistence behind repositories. Repositories own database queries, transactions, and database-specific details.
- Keep shared backend utilities under
/serverby concern, such asserver/security,server/validation,server/errors, orserver/db. - Do not import server modules into client components.
Recommended shape:
app/api/<resource>/route.js
server/controllers/<resource>Controller.js
server/services/<resource>Service.js
server/repositories/<resource>Repository.js
server/db/client.js
server/db/schema.js
server/errors/
server/security/
server/validation/
Engineering Standards
- Promote code reuse, but avoid abstractions that only hide one call site.
- Apply DRY where duplication creates maintenance risk; keep small duplication when it preserves clarity.
- Prefer repository, service, controller, mapper, validator, and policy patterns when they fit the problem.
- Keep modules focused around use cases and ownership boundaries.
- Use dependency injection by parameters or factories when it improves testability without adding ceremony.
- Prefer explicit return objects and typed JSDoc over implicit shape coupling.
- Prefer TypeScript file extensions when the codebase uses TypeScript; keep the same layering either way.
- Use database constraints, transactions, and indexes for invariants that matter.
Security Standard
Security is a top priority. Pause and discuss with the user before implementing a path that creates meaningful risk or changes trust boundaries. For low-risk CRUD changes, refactors, or bug fixes that stay within existing auth and data-access patterns, proceed normally.
Push back or ask for a decision when work touches:
- Authentication, authorization, roles, tenants, sessions, or ownership checks.
- Secrets, environment variables, token handling, webhooks, or third-party credentials.
- User-generated content, file uploads, exports, imports, prompts, or stored AI outputs.
- SQL construction, dynamic filters, raw queries, migrations, or destructive database operations.
- Rate limits, abuse prevention, audit trails, logging, privacy, or data retention.
Default expectations:
- Validate all external input at the boundary before calling services.
- Authorize every read and write against the acting user, resource ownership, and tenant scope.
- Keep secrets server-only and out of logs, client bundles, and serialized responses.
- Prefer parameterized queries over raw SQL.
- Return safe error messages to clients; keep detailed diagnostics in server logs.
- Treat migrations and destructive operations as review-worthy changes.
Backend Workflow
- Inspect existing route, controller, service, repository, schema, and validation patterns before editing.
- Identify the backend boundary being changed and keep files in
/serverunless the code is purely Next.js routing glue. - Design the flow route -> controller -> service -> repository, skipping layers only when the feature is trivial and the boundary remains clear.
- Define validation, authorization, error handling, and transaction needs before writing persistence code.
- Implement the smallest reusable modules that solve the use case.
- Add or update focused tests when behavior, security checks, or persistence contracts change.
- Run relevant verification, usually
npm run typecheck,npm run lint, and targeted tests/build commands when available.
Next.js Route Pattern
Keep route files boring and thin:
export async function POST(request) {
return createThingController({ request });
}
The controller should own body parsing, validation, calling services, and response mapping. Services and repositories should remain portable server modules that can be tested without Next.js route machinery.