Navigation

Node.js

How to Serve Static Files in Express

Serve static files like CSS, JavaScript, and images in Express.js using express.static middleware. Configure multiple static directories and custom routes.

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!

More from Node.js