Table Of Contents
Problem
You need to serve static files (CSS, JavaScript, images, documents) from your Express.js application, allowing clients to access these files directly via URLs.
Solution
const express = require('express');
const path = require('path');
const app = express();
// 1. Basic Static File Serving
app.use(express.static('public'));
// Now files in 'public' folder are accessible:
// http://localhost:3000/style.css -> serves public/style.css
// http://localhost:3000/images/logo.png -> serves public/images/logo.png
// 2. Static Files with Custom URL Prefix
app.use('/assets', express.static('public'));
// http://localhost:3000/assets/style.css -> serves public/style.css
// 3. Multiple Static Directories
app.use(express.static('public'));
app.use(express.static('uploads'));
app.use('/css', express.static('styles'));
app.use('/js', express.static('scripts'));
// Express looks through directories in order for files
// 4. Static Files with Absolute Path
const publicPath = path.join(__dirname, 'public');
app.use(express.static(publicPath));
// 5. Static Files with Options
app.use('/static', express.static('public', {
maxAge: '1d', // Cache for 1 day
etag: false, // Disable ETag generation
index: ['index.html'], // Default files to serve
dotfiles: 'deny' // Deny access to dotfiles
}));
// 6. Conditional Static Serving
app.use('/downloads', (req, res, next) => {
// Add authentication check
const token = req.headers.authorization;
if (!token) {
return res.status(401).json({ error: 'Authentication required' });
}
next();
}, express.static('private-files'));
// 7. Custom Static File Handler
app.get('/custom-static/:filename', (req, res) => {
const filename = req.params.filename;
const filePath = path.join(__dirname, 'custom-files', filename);
// Add custom headers
res.setHeader('X-Custom-Header', 'Static File');
res.setHeader('Cache-Control', 'public, max-age=3600');
// Send file with error handling
res.sendFile(filePath, (err) => {
if (err) {
console.error('File send error:', err);
res.status(404).json({ error: 'File not found' });
}
});
});
// 8. Serve SPA (Single Page Application)
// Serve React/Vue/Angular apps
app.use(express.static(path.join(__dirname, 'build')));
// Catch-all handler for SPA routing
app.get('*', (req, res) => {
res.sendFile(path.join(__dirname, 'build', 'index.html'));
});
// 9. File Type Specific Handling
app.use('/images', express.static('public/images', {
setHeaders: (res, path) => {
if (path.endsWith('.jpg') || path.endsWith('.png')) {
res.setHeader('Cache-Control', 'public, max-age=86400'); // 1 day
}
if (path.endsWith('.gif')) {
res.setHeader('Cache-Control', 'public, max-age=3600'); // 1 hour
}
}
}));
// 10. Development vs Production Static Serving
if (process.env.NODE_ENV === 'production') {
// Production: Serve with aggressive caching
app.use(express.static('public', {
maxAge: '1y',
etag: true,
lastModified: true
}));
} else {
// Development: No caching for easier development
app.use(express.static('public', {
maxAge: 0,
etag: false
}));
}
// Example routes
app.get('/', (req, res) => {
res.send(`
<!DOCTYPE html>
<html>
<head>
<title>Static Files Demo</title>
<link rel="stylesheet" href="/style.css">
</head>
<body>
<h1>Static Files Working!</h1>
<img src="/images/logo.png" alt="Logo">
<script src="/app.js"></script>
</body>
</html>
`);
});
app.get('/api/files', (req, res) => {
// List available static files
res.json({
css: '/style.css',
js: '/app.js',
images: ['/images/logo.png', '/images/banner.jpg'],
downloads: '/downloads/manual.pdf'
});
});
app.listen(3000, () => {
console.log('Server running on port 3000');
console.log('Static files served from:');
console.log('- /public -> public/');
console.log('- /assets -> public/');
console.log('- /css -> styles/');
console.log('- /js -> scripts/');
});
Directory structure example:
project/
├── app.js
├── public/
│ ├── style.css
│ ├── app.js
│ └── images/
│ ├── logo.png
│ └── banner.jpg
├── uploads/
│ └── user-files/
├── styles/
│ └── main.css
└── scripts/
└── bundle.js
Explanation
express.static()
is built-in middleware that serves files from a directory. Files are served relative to the static directory, so public/style.css
becomes accessible at /style.css
.
You can mount static middleware at specific paths using app.use('/prefix', express.static('directory'))
. Express searches through multiple static directories in the order they're defined. Use options like maxAge
for caching and setHeaders
for custom response headers.
Share this article
Add Comment
No comments yet. Be the first to comment!