Express.js là một web framework tối giản, linh hoạt và không áp đặt (unopinionated) chạy trên Node.js. Nó phủ một lớp mỏng lên môi trường chạy (runtime), đủ để bạn dựng ứng dụng web và API mà không che lấp các tính năng cốt lõi của Node.js.
Thay vì áp một bộ quy tắc cứng nhắc, Express chỉ lo phần thiết yếu: xử lý HTTP request và middleware. Phần còn lại là việc của bạn: tổ chức thư mục ra sao, lắp thêm thư viện nào từ npm.

Express.js là gì?
Express.js là một lớp mỏng nằm trên Node.js. Nó không tái định nghĩa cách Node.js hoạt động. Nó chỉ dọn giúp bạn mấy việc lặp đi lặp lại: định tuyến, đọc dữ liệu gửi lên, dựng phản hồi trả về. Framework này đứng trên bốn trụ cột: ứng dụng web (đơn trang hoặc đa trang), API (các dịch vụ RESTful), hiệu năng (giữ nguyên tốc độ của Node.js) và hệ thống middleware.

Nhưng thứ đáng nói nhất lại nằm ở chữ "unopinionated", tức không áp đặt. Express không bắt bạn dùng một cấu trúc thư mục cụ thể, cũng không chọn sẵn ORM hay template engine nào. Con dao hai lưỡi. Một mặt, bạn tối ưu hệ thống theo đúng nhu cầu của mình. Mặt khác, nếu cả đội không thống nhất trước các quy ước rõ ràng, dự án trượt rất nhanh thành một mớ code rối và nợ kỹ thuật cứ thế dồn lại. Tôi cho rằng đây mới là câu hỏi quyết định bạn có nên chọn Express hay không, chứ không phải mấy dòng benchmark.
Đổi lại, cái được thì rõ. Viết bằng JavaScript thuần nghĩa là client và server nói cùng một ngôn ngữ, đỡ hẳn khoản chuyển ngữ cảnh khi bạn ôm cả hai đầu. Dựa lưng vào hệ sinh thái npm khổng lồ, gần như bài toán nào cũng có sẵn package để lắp vào.
Một ứng dụng Express tối thiểu trông như thế nào?
Khởi tạo một server Express chỉ cần vài dòng:
const express = require("express");
const app = express();
const port = 3000;
app.get("/", (req, res) => {
res.send("Hello World!");
});
app.listen(port, () => {
console.log(`Server listening on port ${port}`);
});Đối tượng app là thực thể chính, do hàm express() tạo ra. Phương thức app.get nhận hai tham
số: đường dẫn và một hàm callback xử lý. Callback này nhận hai đối tượng cốt lõi: req chứa mọi
thông tin từ phía client, còn res dùng để phản hồi.
Khi trình duyệt gửi request đến port 3000 với đường dẫn /, Express khớp route rồi chạy callback
tương ứng. Lệnh res.send vừa gửi dữ liệu về client, vừa tự thiết lập các header cần thiết và kết
thúc chu kỳ request-response. Nhờ vậy kết nối không bị treo.
Riêng app.listen có một thay đổi đáng lưu ý ở Express 5: khi server gặp lỗi, callback bạn truyền
vào sẽ được gọi kèm theo lỗi đó, thay vì lỗi bị ném ra như ở bản 4. Trách nhiệm xử lý chuyển về
phía callback, nên hãy kiểm tra tham số lỗi trước khi hồn nhiên log dòng "đang lắng nghe".
Middleware: cơ chế cốt lõi của Express
Middleware là các hàm trung gian nằm giữa request và response, những chốt kiểm soát trong luồng xử
lý. Một hàm middleware tiêu chuẩn nhận ba tham số: req, res và next. Nó chạy logic của mình
(xác thực, ghi log, đọc body), rồi hoặc kết thúc chu kỳ bằng một lệnh phản hồi, hoặc gọi next() để
chuyển quyền cho hàm kế tiếp trong stack. Bỏ qua cả hai, request sẽ treo vô thời hạn.

Express phân middleware thành ba nhóm:
- Middleware tích hợp sẵn: Express đóng gói sẵn năm hàm.
express.staticphục vụ file tĩnh,express.jsonđọc body dạng JSON,express.urlencodedđọc dữ liệu form, cùngexpress.rawvàexpress.textcho payload dạng Buffer và văn bản. - Middleware bên thứ ba: cài từ npm, ví dụ
morganđể ghi log request haycookie-parserđể đọc cookie. - Middleware tự viết: phần logic nghiệp vụ riêng của bạn.
Thứ tự khai báo là yếu tố sống còn, vì Express chạy middleware đúng theo trình tự chúng xuất hiện
trong code. Lỗi phổ biến nhất: đặt express.json() sau các route handler, thế là req.body thành
undefined. Không log, không cảnh báo. Bạn cứ thế ngồi soi xem dữ liệu bốc hơi ở đâu. Tương tự, đặt
error handler lên trên các route thì nó sẽ chẳng bao giờ bắt được lỗi từ những route đó.
Một middleware ghi log đơn giản trông như sau:
app.use((req, res, next) => {
console.log(`${new Date().toISOString()} - ${req.method} ${req.url}`);
next();
});Định tuyến và express.Router
Định tuyến quy định server phản hồi ra sao với từng endpoint, theo từng phương thức HTTP cụ thể: GET,
POST, PUT, DELETE. Express ánh xạ chúng qua app.METHOD(). Ngoài ra còn app.all(), dùng khi bạn
muốn áp một logic chung cho mọi phương thức tại cùng một đường dẫn, chẳng hạn bắt buộc xác thực.

Express cho phép trích dữ liệu động qua tham số route. Với route /users/:id, giá trị thật nằm ở
req.params.id. Đây là nền tảng của mọi API RESTful. Ở Express 5, phần khớp đường dẫn chuyển sang
path-to-regexp v8 với cú pháp chặt hơn hẳn: ký tự đại diện phải được đặt tên (/*splat thay vì
/*), và đoạn tùy chọn dùng cặp ngoặc nhọn {} thay cho dấu ? trước đây. Nếu bạn đang nâng cấp
từ bản 4, đây là chỗ tôi khuyên nên rà lại trước tiên.
Khi ứng dụng lớn dần, express.Router gần như bắt buộc. Router hoạt động như một ứng dụng con: bạn
tách logic của từng cụm tính năng (/users, /orders) ra file riêng, rồi gắn vào ứng dụng chính
bằng app.use(). Khi lồng router vào nhau, tham số của route cha mặc định không truyền xuống; thêm
tùy chọn { mergeParams: true } lúc khởi tạo Router để route con đọc được chúng.
Xử lý lỗi trong Express
Express có sẵn một bộ xử lý lỗi mặc định nằm cuối stack middleware. Lỗi nào phát sinh mà không ai bắt
sẽ rơi vào đó và trả về mã 500. Ở môi trường phát triển, nó kèm luôn stack trace; khi NODE_ENV đặt
là production, phần stack trace bị lược đi. Đó đúng là hành vi bạn muốn, vì đẩy stack trace về
client là một lỗ hổng bảo mật thực sự.

Cải tiến lớn nhất của Express 5 là tự động bắt lỗi từ những Promise bị reject trong handler async.
Bạn không còn phải bọc mọi thứ trong try-catch rồi gọi next(err) thủ công như ở bản 4. Riêng
khoản này thôi đã đủ lý do để nâng cấp. Nhưng với các API kiểu callback cũ như fs.readFile, bạn vẫn
phải tự bắt lỗi và đẩy vào next(err).
Một middleware xử lý lỗi tự viết luôn phải có đủ bốn tham số: (err, req, res, next). Thiếu tham số
err, Express xem đây là middleware thường và bỏ qua toàn bộ logic xử lý lỗi bạn viết. Nó cũng phải
được khai báo sau cùng, sau tất cả app.use() và route. Một chi tiết dễ quên: nếu lỗi xảy ra khi
header đã gửi đi rồi, hãy gọi next(err) để nhường lại cho bộ xử lý mặc định đóng kết nối.
Express 5 khác Express 4 ở đâu?
Express 5 tập trung hiện đại hóa phần lõi và giảm nợ kỹ thuật, chứ không thêm tính năng mới:
- Yêu cầu hệ thống: cần Node.js 18 trở lên.
- Loại bỏ phương thức cũ:
app.del()bị xóa hẳn, thay bằngapp.delete().req.param()cũng biến mất, buộc bạn truy cập tường minh vàoreq.params,req.queryhoặcreq.body.res.sendfile()đổi thànhres.sendFile(). - Chuẩn hóa tên phương thức:
req.acceptsCharset()thànhreq.acceptsCharsets(), tương tự với Encodings và Languages. - Thay đổi về khớp đường dẫn: ký tự đại diện bắt buộc phải có tên, và dấu
?không còn dùng được trực tiếp trong chuỗi đường dẫn. - Thay đổi MIME type: file
.jsnay được phục vụ với MIME typetext/javascriptthay vìapplication/javascript. - Mặc định mới:
express.urlencodedđặt tùy chọnextendedvềfalse, vàexpress.static.mimekhông còn được export, dùng packagemime-typesđộc lập thay thế.

Đội Express cung cấp sẵn bộ codemod tự động hóa phần lớn việc chuyển đổi, chạy qua
@expressjs/v5-migration-recipe. Được đến đâu hay đến đó; riêng phần khớp đường dẫn thì vẫn nên tự
soi lại bằng mắt.
Express có còn được duy trì tốt không?
Có, và rõ rệt hơn nhiều người nghĩ. Năm 2024, Express đạt trạng thái "Impact Project" của OpenJS Foundation, mức ghi nhận vai trò then chốt của dự án trong hệ sinh thái JavaScript. Technical Committee được bổ sung tám thành viên mới, trong đó có Blake Embrey, Ulises Gascón và Wes Todd.
Bảo mật trở thành trụ cột chính. Đợt kiểm toán bảo mật năm 2024 khiến dự án áp dụng OSSF Scorecard để theo dõi sức khỏe theo thời gian thực. Với các tổ chức còn chạy phiên bản cũ, Express hợp tác cùng HeroDevs cung cấp gói hỗ trợ dài hạn để tiếp tục vá bảo mật.
Lộ trình 2025–2026, với hậu thuẫn từ Sovereign Tech Fund, xoay quanh ba việc: tự động hóa quy trình
phát hành trên npm để bớt sai sót thủ công, chuyển sang scoped package @expressjs/ để quản lý hệ
sinh thái gọn hơn, và tối ưu sâu phần lõi. Nhóm kỳ vọng những cải tiến hiệu năng này hoàn tất vào
giữa năm 2026. Với một dự án nhiều năm bị đồn là đã ngủ đông, đó là một quãng hồi sức đáng nể.
Khi nào nên chọn Express — và khi nào không?
Chọn Express khi bạn cần sự linh hoạt tối đa và muốn kiểm soát chi tiết từng thành phần trong middleware stack. Nó là lựa chọn tự nhiên cho các API nhẹ, microservice và những dịch vụ trung gian. Ở những chỗ đó, một framework đồ sộ chỉ làm vướng chân.

Đừng chọn Express nếu bạn muốn một framework dọn sẵn mọi thứ, có cấu trúc chuẩn và quy ước rõ ràng ngay từ đầu để đội đông người khỏi phải tự thiết kế kiến trúc. Express đưa cho bạn quyền tự quyết, và đi kèm quyền đó là trách nhiệm giữ cho kiến trúc khỏi rối. Nếu đội bạn chưa sẵn sàng nhận phần trách nhiệm ấy, hãy chọn thứ khác.
Tài liệu tham khảo
- Express.js · Node.js web application framework
- Express/Node introduction — MDN
- Using middleware · Express.js 5.x
- Routing · Express.js 5.x
- Error Handling · Express.js 5.x
- Upgrade to Express v5 · Express.js
- What's New in Express.js v5.0 — Better Stack Community
- A New Chapter for Express.js: Triumphs of 2024 and an ambitious 2025 · Express.js