Skip to main content
Practice Problems

How to serve static files and improve performance in Express.js?

Static Files & Performance in Express.js

Serving static files (HTML, CSS, JS, images) efficiently and compressing responses are fundamental to Express.js performance.


Serving Static Files

express.static() is Express's built-in middleware for serving static assets:

js
const express = require('express'); const path = require('path'); const app = express(); // Serve everything in the 'public' folder app.use(express.static('public')); // With absolute path (recommended) app.use(express.static(path.join(__dirname, 'public'))); // With URL prefix app.use('/static', express.static(path.join(__dirname, 'public'))); // → http://localhost:3000/static/style.css
public/ index.html → GET / style.css → GET /style.css js/app.js → GET /js/app.js images/logo.png → GET /images/logo.png

Static Middleware Options

js
app.use(express.static('public', { maxAge: '1d', // cache for 1 day (browser caching) etag: true, // enable ETag for cache validation lastModified: true, // enable Last-Modified header index: 'index.html', // default file for directories dotfiles: 'ignore', // hide .env, .git files extensions: ['html'], // try adding .html extension }));

Response Compression

bash
npm install compression
js
const compression = require('compression'); // Compress all responses (gzip / deflate) app.use(compression()); // With options app.use(compression({ level: 6, // compression level 1-9 (6 is default) threshold: 1024, // only compress responses > 1KB filter: (req, res) => { // Don't compress if client requests no compression if (req.headers['x-no-compression']) return false; return compression.filter(req, res); } }));

Cache-Control Headers

js
// Immutable assets (hashed filenames like app.abc123.js) app.use('/static', express.static('public', { maxAge: '1y', // cache for 1 year immutable: true // tell browser file will never change })); // Dynamic HTML — never cache app.use((req, res, next) => { if (req.path.endsWith('.html')) { res.set('Cache-Control', 'no-cache, no-store, must-revalidate'); } next(); });

Serve a React/Vue Build

js
// Serve React/Vue build from Express app.use(express.static(path.join(__dirname, 'client/build'))); // For React Router — send index.html for all non-API routes app.get('*', (req, res) => { if (!req.path.startsWith('/api')) { res.sendFile(path.join(__dirname, 'client/build', 'index.html')); } });

Multiple Static Directories

js
// Express checks directories in order app.use(express.static('public')); app.use(express.static('uploads')); app.use(express.static('node_modules/bootstrap/dist'));

Performance Tips

TechniqueImpact
Enable compressionReduce response size 60-80%
Set Cache-Control headersReduce repeated requests
Use CDN for assetsGlobal low-latency delivery
Serve from nginxFar faster than Node.js for static
Use HTTP/2Multiplexing, header compression
Bundle & minify assetsFewer and smaller requests

Production: Use nginx

In production, serve static files from nginx in front of Express:

nginx
# nginx.conf location /static/ { root /var/www/myapp/public; expires 1y; add_header Cache-Control "public, immutable"; } location / { proxy_pass http://localhost:3000; }

This offloads static file serving from Node.js entirely.


Summary

Use express.static() to serve files and add compression middleware to gzip responses. Set appropriate Cache-Control headers for long-lived assets. In production, offload static files to nginx or a CDN for maximum performance.

Short Answer

Interview ready
Premium

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

Finished reading?
Practice Problems