Skip to main content

What are controllers in Express applications?

In short:

A controller is where the main logic of processing the request and building the response to the client happens.

1. What a controller is in Express

In Express.js, a controller is a function (or set of functions) that gets called when a user hits a particular route.

It:

  • receives the req (request) and res (response) objects;
  • calls the needed services, models, or databases;
  • returns a response (JSON, HTML, a file, etc.) to the user;
  • handles errors when needed.

A simple controller example

javascript
// controllers/userController.js exports.getAllUsers = async (req, res, next) => { try { const users = await User.find(); // reach out to the model res.json(users); // send the response to the client } catch (err) { next(err); // pass the error to middleware } };

And mounting this controller inside a route:

javascript
// routes/users.js const express = require('express'); const router = express.Router(); const userController = require('../controllers/userController'); router.get('/', userController.getAllUsers); module.exports = router;

Now GET /users calls the getAllUsers() function from the controller.

2. What a controller does

StageWhat it does
Receives dataReads request parameters: req.params, req.query, req.body, req.headers
Calls business logicThrough services or models (database work, checking conditions, authorization, etc.)
Builds the responseSends the client res.json(), res.status(), res.send(), res.redirect(), etc.
Handles errorsVia try...catch and next(err), passing them to error middleware

3. Why controllers are needed

ReasonExplanation
Separation of concernsThe controller handles requests, not routing.
Cleaner codeThe code in routes stays minimal and easy to follow.
ReuseThe same controller can be mounted into different routes or projects.
Easier testingControllers can be tested independently of the Express application.
ScalabilityAs the API grows, controllers can be split across modules (users, products, orders…).

4. An example Express application structure with controllers

javascript
src/ ├── app.js ├── routes/ │ ├── users.js │ ├── products.js │ └── auth.js ├── controllers/ │ ├── userController.js │ ├── productController.js │ └── authController.js ├── services/ │ ├── userService.js │ └── productService.js ├── middlewares/ │ ├── authMiddleware.js │ └── errorHandler.js └── db/ └── index.js

Here:

  • routes/ only defines the paths (/users, /products, etc.);
  • controllers/ holds the functions that run when those routes are hit;
  • services/ holds the business logic (DB work, APIs, etc.).

5. A production-grade controller example

javascript
// controllers/productController.js const productService = require('../services/productService'); exports.createProduct = async (req, res, next) => { try { const product = await productService.create(req.body); res.status(201).json(product); } catch (err) { next(err); // centralized error handling } }; exports.getProduct = async (req, res, next) => { try { const product = await productService.getById(req.params.id); if (!product) return res.status(404).json({ message: 'Not found' }); res.json(product); } catch (err) { next(err); } };

6. Summary

Controllers are functions that do the main work of handling an HTTP request: they receive data from the client, call business logic, and return a response.

Their main purpose is to:

  • separate routes from logic;
  • make the code structured, readable, and scalable;
  • allow handlers to be tested and reused independently of Express.

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.