Use Express middleware packages like helmet, cors, and compression in your LumenJS app. Place _middleware.ts files alongside your pages. They nest like layouts.
Middleware chains nest: a request to /admin/dashboard runs root middleware first, then admin/_middleware.ts, then the page handler.
Install any Express-compatible middleware and export it as a default array:
// pages/_middleware.ts import helmet from 'helmet'; import responseTime from 'response-time'; export default [ helmet({ contentSecurityPolicy: false }), responseTime(), ];
cors and helmet work out of the box.
| Package | Purpose | Install |
|---|---|---|
helmet | Security headers (XSS, HSTS, clickjacking, etc.) | npm i helmet |
cors | Cross-origin resource sharing | npm i cors |
compression | Gzip/Brotli response compression | npm i compression |
response-time | X-Response-Time header | npm i response-time |
express-rate-limit | Rate limiting | npm i express-rate-limit |
Write your own using the standard (req, res, next) signature:
// pages/admin/_middleware.ts const authGuard = (req, res, next) => { if (!req.headers['authorization']) { res.statusCode = 403; res.setHeader('Content-Type', 'text/html'); res.end('<h1>Access Denied</h1>'); return; // don't call next() - blocks the request } next(); }; export default [authGuard];
| Request to | Middleware chain |
|---|---|
/ | pages/_middleware.ts |
/admin/dashboard | pages/_middleware.ts → pages/admin/_middleware.ts |
/api/users | pages/_middleware.ts → pages/api/_middleware.ts |
_middleware.ts files without restarting the server.
This website uses helmet and response-time from npm right now. Open DevTools → Network tab and inspect any page's response headers:
| Header | Source |
|---|---|
Strict-Transport-Security | helmet |
X-Content-Type-Options: nosniff | helmet |
X-Frame-Options: SAMEORIGIN | helmet |
Cross-Origin-Opener-Policy | helmet |
Referrer-Policy: no-referrer | helmet |
X-Response-Time: 12ms | response-time |
The /demo/* pages have an additional nested middleware that blocks access when ?locked=true is in the URL:
req/res objects, not the Lit component lifecycle.