Guide
Serving Static Assets with Express.js: A Step‑by‑Step Guide
Learn how to serve CSS, JS, images, and HTML with Express.js static middleware, including setup, verification, and error‑handling strategies.
Published by Tasadduq Burney
04 Jul 2026, 22:25 UTC
3 min122.3K views0

Desired outcome
Configure an Express.js application so that requests for CSS, JavaScript, images, or HTML files are served directly from a filesystem directory without writing custom route handlers.
Prerequisites
- Node.js version 14 or newer installed.
- npm available to install packages.
- An existing Node.js project (or a new one created with
npm init -y). - The Express package installed:
npm i express. - A directory that holds the static files you want to expose, e.g.,
public/containingstyle.css,app.js, and anindex.htmlfile.
Focused procedure
- Create the Express app
const express = require('express'); const app = express(); const port = 3000; - Mount the static middleware
Use
express.staticto map thepublic/folder to the root URL. Adjust caching and ETag behavior as needed.// Serve files from ./public, cache for 1 day, disable ETag generation app.use(express.static('public', { maxAge: '1d', // controls the Cache‑Control header etag: false // omit ETag to reduce header size })); - Start the server
app.listen(port, () => { console.log(`Static server listening at http://localhost:${port}`); });
Expected checks
- HTTP status and content – Run
curl -I http://localhost:3000/style.css. You should see a200 OKstatus, aContent-Type: text/cssheader, and aCache-Control: public, max-age=86400header (reflecting themaxAgeoption). - Missing file – Request a non‑existent path, e.g.,
curl -I http://localhost:3000/does-not-exist.txt. Expect a404 Not Foundresponse because the middleware passes control to the next handler. - Directory listing – Access
http://localhost:3000/without anindex.htmlinsidepublic/. The response should be404 Not Found(directory listings are disabled by default). - Browser verification – Open
http://localhost:3000/index.htmlin a browser. Confirm the page loads and that the Network tab shows200for all referenced assets. - Automated test (optional) – Using
supertest:const request = require('supertest'); request(app) .get('/script.js') .expect(200) .expect('Content-Type', /javascript/) .end((err, res) => { if (err) throw err; });
Recovery options
- Custom 404 handler – Place a middleware after
express.staticto provide a friendly error page or JSON response.app.use((req, res) => { res.status(404).send('Sorry, we cannot find that!'); }); - Earlier error triggering – If you prefer static middleware to throw an error instead of falling through, set
fallthrough: false. This will cause a missing file to invoke Express’s error‑handling chain.app.use(express.static('public', { fallthrough: false })); app.use((err, req, res, next) => { if (err.status === 404) { res.status(404).send('Asset not found'); } else { next(err); } });
Additional considerations
- Security – Ensure the static folder contains only public assets. Do not point
express.staticat a directory that holds source code, configuration files, or environment variables. - Performance – For high‑traffic sites, consider offloading static serving to a reverse proxy (e.g., NGINX) or a CDN, which can handle large files and concurrent requests more efficiently than Node.js’s event loop.
- Cache control – Adjust
maxAgeper file type if needed, usingexpress.staticoptions or a middleware likeconnect-cache-controlto fine‑tune headers.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.