Express · Lesson 13 of 15
Layered Project Structure
Split routes, services and data access so handlers stay thin.
- Advanced
- 15 min read
- 3 objectives
Before this lessonLesson 12: WebSockets
What you will learn
- Draw the layers
- Keep SQL out of routes
- Add a request id
Your Progress
0 of 15 lessons 0%
- Lessons0 / 15
- Completed0
- Est. time left~ 4 hours
Create a free account to keep your progress on every device.
A growing Express app becomes unreadable when SQL, validation and HTTP live in one file. A simple layering is enough.
Folders
src/
app.js # middleware, mounts routers, error handler
server.js # listen
routes/tasks.js
services/tasks.js # business rules
db/tasks.js # SQL or Prisma
middleware/auth.js
lib/async.jsThin handlers
// routes/tasks.js
router.post("/", validate(CreateTask), wrap(async (req, res) => {
const task = await tasksService.create(req.userId, req.valid.body);
res.status(201).json(task);
}));
// services/tasks.js
export async function create(userId, input) {
return db.tasks.insert({ ...input, userId });
}Services throw domain errors (err.status = 409); the HTTP layer maps them. Tests can hit services without supertest.
