Skip to main content

Command Palette

Search for a command to run...

Storing Uploaded Files and Serving Them in Express

Published
β€’4 min read

When building real-world applications, handling file uploads (images, PDFs, videos, etc.) is a common requirement. But uploading is just one part β€” storing, serving, and securing those files is equally important.

In this guide, we’ll break down how file storage works in Node.js with Express, along with best practices used in production systems.

πŸ“¦ Where Uploaded Files Are Stored

When a user uploads a file, the backend must decide where to store it. Broadly, there are two approaches:

1. Local File System (Server Storage)

Files are stored directly on the server's disk.

Example structure:

project-root/
β”‚
β”œβ”€β”€ uploads/
β”‚   β”œβ”€β”€ images/
β”‚   β”‚   β”œβ”€β”€ img1.jpg
β”‚   β”‚   β”œβ”€β”€ img2.png
β”‚   β”‚
β”‚   β”œβ”€β”€ documents/
β”‚       β”œβ”€β”€ file1.pdf
β”‚
β”œβ”€β”€ server.js

How it works:

  • A middleware like multer saves files into a folder (uploads/)

  • File path is stored in your database

  • Later, files are served via Express

2. External Storage (Cloud / Object Storage)

Instead of storing files locally, you use services like:

  • AWS S3

  • Cloudinary

  • Firebase Storage

How it works:

  • File is uploaded directly (or via backend) to cloud storage

  • You store the file URL in your database

  • Files are served directly from CDN

βš–οΈ Local Storage vs External Storage

Feature Local Storage External Storage
Setup Simple Requires configuration
Scalability Poor Highly scalable
Performance Limited CDN optimized
Cost Free (initially) Pay-as-you-scale
Reliability Risky (server crash = data loss) Highly reliable

πŸ‘‰ Rule of thumb:

  • Use local storage for small projects / learning

  • Use external storage for production apps

πŸ“ Serving Static Files in Express

Express provides a built-in middleware to serve static files:

const express = require("express");
const path = require("path");

const app = express();

// Serve files from "uploads" folder
app.use("/uploads", express.static(path.join(__dirname, "uploads")));

What this does:

  • Maps /uploads URL path to the actual uploads/ folder

  • Makes files publicly accessible

🌐 Accessing Uploaded Files via URL

If you have a file stored like:

uploads/images/profile.jpg

You can access it via:

http://localhost:3000/uploads/images/profile.jpg

πŸ‘‰ This works because of:

app.use("/uploads", express.static("uploads"));

πŸ› οΈ Upload Example Using Multer

const multer = require("multer");

const storage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, "uploads/images");
  },
  filename: function (req, file, cb) {
    cb(null, Date.now() + "-" + file.originalname);
  }
});

const upload = multer({ storage: storage });

app.post("/upload", upload.single("file"), (req, res) => {
  res.send({
    message: "File uploaded successfully",
    filePath: req.file.path
  });
});

πŸ” Security Considerations for File Uploads

This is where most beginners make mistakes. File uploads are a major attack surface.

1. Validate File Type

Never trust client input.

fileFilter: (req, file, cb) => {
  if (file.mimetype.startsWith("image/")) {
    cb(null, true);
  } else {
    cb(new Error("Only images allowed"), false);
  }
}

2. Limit File Size

limits: { fileSize: 5 * 1024 * 1024 } // 5MB

3. Avoid Executable Files

Block .js, .exe, .sh, etc.

4. Use Unique File Names

Prevent overwriting:

Date.now() + "-" + file.originalname

5. Store Outside Public Root (Advanced)

Instead of directly exposing /uploads, use a controller:

app.get("/file/:name", (req, res) => {
  res.sendFile(path.join(__dirname, "uploads", req.params.name));
});

6. Scan Files (Production)

Use antivirus or scanning tools for:

  • PDFs

  • Documents

  • User uploads

Here's a prod grade structure ( it has sharding, careful if following this )

πŸ“š Static File Serving Concept (Important)

Static files are files that:

  • Don’t change dynamically

  • Are served directly to the client

Examples:

  • Images

  • CSS files

  • PDFs

Express acts like a file server when using:

express.static()

πŸ‘‰ Instead of writing routes manually, Express:

  • Locates the file

  • Streams it to the client

  • Sets correct headers

Here's a prod grade example -

🧠 Best Practices Summary

  • Use multer for handling uploads

  • Separate folders by file type (images, docs, etc.)

  • Never trust user-uploaded files

  • Prefer cloud storage in production

  • Use CDN for faster delivery

  • Store only file paths/URLs in DB (not actual files)

πŸš€ Final Thought

File handling may look simple, but at scale, it becomes a system design problem involving:

  • Storage architecture

  • Security layers

  • CDN optimization

  • Cost management

Storing Uploaded Files and Serving Them in Express