Storing Uploaded Files and Serving Them in Express
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
multersaves 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
/uploadsURL path to the actualuploads/folderMakes 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
multerfor handling uploadsSeparate 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