Split a Monolithic Express Router into Domain Routes
Devin breaks a 2,000-line Express router into domain-specific route files with shared middleware — then updates every import and verifies all tests pass.Show Devin the monolith
You know the file — one Express router that grew for eighteen months. Every endpoint for every domain lives in Tell Devin exactly what you want the target structure to look like.
src/routes/index.ts: user registration next to payment webhooks next to product search. Inline auth checks are copy-pasted across 40 handlers. Nobody wants to touch it because a change to the orders logic might break the user endpoints three hundred lines above.Here’s what the top of the file typically looks like:src/routes/index.ts (before — 2,000 lines)
Guide Devin with conventions
Devin reads your codebase to infer patterns, but refactoring is where Knowledge entries pay off the most. Add entries for conventions Devin should follow:
- Router patterns — “Each domain router uses
Router()and is mounted withapp.use('/domain', domainRouter)in the root” - Middleware — “Auth middleware lives in
src/middleware/and is always imported, never defined inline” - Error handling — “All route handlers use our
asyncHandlerwrapper fromsrc/lib/asyncHandler.ts— never raw try/catch”
src/routes/admin.ts, which is already cleanly separated” to your prompt.You can also use Advanced Devin to generate Knowledge entries for you — just describe your conventions and it will create well-structured entries you can review and save.Review Devin's PR
Devin maps every endpoint, traces the import graph, extracts shared logic, creates the domain files, rewires the root router, and runs your test suite. Here’s what the PR typically looks like:Here’s what the clean root router looks like after the split:And a domain route file with the shared middleware properly imported:Every URL path stays identical —
src/routes/index.ts (after — 15 lines)
src/routes/orders.ts (after — excerpt)
/orders is now handled by ordersRouter mounted at /orders, so existing clients and tests work without changes.(Optional) Check out the branch and test locally
For a structural refactor like this, it’s worth pulling the branch and verifying locally before merging. Check it out in Windsurf or your preferred IDE, boot the app, and hit a few endpoints to confirm routing, middleware, and error handling all behave the same as before.If anything looks off, leave a comment on the PR — Devin will pick it up and push a fix.
