# 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:

```plaintext
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:

```js
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:

```plaintext
uploads/images/profile.jpg
```

You can access it via:

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

👉 This works because of:

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

## 🛠️ Upload Example Using Multer

```js
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.

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

### 2\. Limit File Size

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

### 3\. Avoid Executable Files

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

### 4\. Use Unique File Names

Prevent overwriting:

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

### 5\. Store Outside Public Root (Advanced)

Instead of directly exposing `/uploads`, use a controller:

```js
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 )

![](https://cdn.hashnode.com/uploads/covers/69517129b3f42beb72514f64/91092f21-7090-417c-b75d-211718732df4.png align="center")

## 📚 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:

```js
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 -

![](https://cdn.hashnode.com/uploads/covers/69517129b3f42beb72514f64/69dcc7f2-f1cb-4b9e-8e59-d70c197c83ef.png align="center")

## 🧠 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
