Storing Uploaded Files and Serving Them in Express
Where uploaded files are stored
When a user uploads a file via an API (e.g., using multipart/form-data), the backend needs to decide where to persist it.
Typical flow:
Client uploads file → API endpoint
Middleware (like
multer) processes the fileFile is stored either:
Locally (disk)
Remotely (cloud storage)
Example using multer (local storage):
import multer from "multer";
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, "uploads/");
},
filename: function (req, file, cb) {
cb(null, Date.now() + "-" + file.originalname);
},
});
const upload = multer({ storage });
This stores files in a local uploads/ directory.
Local storage vs external storage concept
Choosing storage is an architectural decision, not just an implementation detail.
Local Storage (Disk)
Pros:
Simple setup
Fast access (low latency)
No external dependencies
Cons:
Not scalable across multiple servers
Risk of data loss on server crash
Difficult to manage backups
External Storage (Cloud)
Popular services:
Amazon S3
Cloudinary
Google Cloud Storage
Pros:
Highly scalable
Durable and reliable
CDN support for fast delivery
Cons:
Requires setup and credentials
Slightly higher latency
Costs involved
Serving static files in Express
Once files are stored locally, you need to serve them over HTTP.
Basic setup:
import express from "express";
const app = express();
app.use("/uploads", express.static("uploads"));
What this does:
Maps
/uploadsURL path →uploads/folderAny file inside
uploads/becomes publicly accessible
Accessing uploaded files via URL
If a file is stored as:
uploads/1714738293-profile.png
You can access it at:
http://localhost:3000/uploads/1714738293-profile.png
Example API response:
{
"imageUrl": "http://localhost:3000/uploads/1714738293-profile.png"
}
This URL can be used directly in frontend apps (<img src=... />).
Security considerations for uploads
Maps
/uploadsURL path →uploads/folderAny file inside
uploads/becomes publicly accessible
🌐 Accessing Uploaded Files via URL
If a file is stored as:
uploads/1714738293-profile.png
You can access it at:
http://localhost:3000/uploads/1714738293-profile.png
Example API response:
{
"imageUrl": "http://localhost:3000/uploads/1714738293-profile.png"
}
This URL can be used directly in frontend apps (<img src=... />).
Security Considerations for File Uploads
This is where most developers make mistakes. File uploads are a major attack vector.
Validate File Types
Never trust file.mimetype blindly.
const allowedTypes = ["image/png", "image/jpeg"];
if (!allowedTypes.includes(file.mimetype)) {
throw new Error("Invalid file type");
}
Limit File Size
const upload = multer({
storage,
limits: { fileSize: 2 * 1024 * 1024 }, // 2MB
});
Prevents DoS via large uploads.
Avoid Executable Files
Never allow:
.js.exe.sh
These can be executed on your server if misconfigured.
Rename Files Safely
Avoid using original filenames directly.
✔️ Good:
timestamp-randomstring.png
❌ Bad:
../../../etc/passwd
Use Separate Storage Server (Production)
Serving files directly from your API server:
Increases load
Reduces scalability
Instead:
Upload → Cloud (e.g., S3)
Serve via CDN
Authentication (if needed)
Not all files should be public.
Options:
Signed URLs (S3)
Auth middleware before serving files

