Skip to main content

Command Palette

Search for a command to run...

Storing Uploaded Files and Serving Them in Express

Updated
7 min read
Storing Uploaded Files and Serving Them in Express
S
A front-end developer who’s always learning, building projects, and writing blogs to simplify web concepts

When people build web apps, file uploads show up very quickly. A user may upload a profile photo, a resume, a product image, or a PDF. That file needs to go somewhere, and later it often needs to be shown back to the user. Express makes this possible in a very clean way.

In this article, we will look at where uploaded files are stored, how local storage works, how static files are served in Express, how uploaded files can be accessed through a URL, and what you should keep in mind for security.


Where uploaded files are stored

When a file is uploaded from the frontend, it reaches your Express server through a request. The server then saves that file in a place you choose.

Most beginners start with local storage. That means the file is saved inside a folder on the same machine where the Express app is running.

A simple folder structure looks like this:

In this setup, the uploads folder is the storage location.

What this means in practice is simple. If a user uploads photo.png, Express can save it as something like 1700000000-photo.png inside the uploads folder. The file is now physically present on the server.

This is the easiest way to understand uploads because the file stays close to your application and is easy to access during development.


Local storage vs external storage

When handling file uploads, there are two common ways to store files. The choice depends on the scale and purpose of your application.

Local storage means the uploaded file is saved directly on your server, usually inside a folder like uploads.

A typical flow looks like this:

User uploads file → Express receives request → File is saved in uploads folder

In this setup, the file physically exists on the same machine where your application is running.

This approach is simple and works well for small projects, practice applications, or assignments. It is quick to implement and does not require any external setup. However, it has limitations. If the server is restarted, redeployed, or crashes, files can be lost unless you have a proper backup system. It also becomes difficult to manage as the application grows.

External storage means the file is not stored on your server. Instead, it is uploaded to a separate storage service such as cloud storage.

A typical flow looks like this:

User uploads file → Express processes request → File is uploaded to cloud storage → File URL is stored

Here, your server acts as a bridge between the user and the storage service.

This method is more suitable for production applications. It is more reliable, easier to scale, and better for handling large amounts of data. Since files are stored externally, your server remains lightweight and easier to manage. Instead of storing the file itself, your application stores only the file URL.


Uploading files in Express

To accept file uploads in Express, developers commonly use a middleware package such as multer. It helps process multipart form data, which is the format used when files are sent from a form.

For Example:

import express from "express";
import multer from "multer";

const app = express();

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

const upload = multer({ storage });

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

app.listen(3000);

What this code does is straightforward.

multer receives the uploaded file.

diskStorage() tells multer to save that file inside the uploads folder.

filename changes the name so files do not overwrite each other. For example, if two users upload a file called image.png, both cannot be saved with the exact same name. Adding a timestamp makes the filename unique.

upload.single("file") means the form is sending one file using the field name file.

The route then responds with a success message after the upload is complete.


Serving static files in Express

Saving a file is only half the job. After uploading, the file often needs to be viewed or downloaded. That is where static file serving comes in.

Express can make a folder public by using express.static().

Example:

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

This line tells Express to expose the uploads folder through the /uploads URL path.

That means if a file exists here:

uploads/photo-1700000000.png

It can be accessed in the browser like this:

http:/localhost:3000/uploads/photo-1700000000.png

This works because Express looks inside the uploads folder whenever someone visits a URL that starts with /uploads.

So instead of writing a separate route for every file, Express handles the file serving automatically.


How file access through URL works

The idea here is simple.

When a browser opens a URL like:

http://localhost:3000/uploads/resume.pdf

Express checks whether resume.pdf exists inside the uploads folder.

If it exists, the file is sent back to the browser.

If it does not exist, Express returns an error.

That is the main benefit of static file serving. It gives your uploaded files a direct public path.

This is one of the easiest ways to serve images, PDFs, and other static assets in a Node.js app.


A clean upload and access flow

Here is the full picture.

This is the basic file lifecycle in an Express application.

First the file is stored.

Then it is exposed through a public URL.

Then users can access it whenever needed.


Security considerations for uploads

File uploads look simple, but they can become dangerous if you are not careful. A server that accepts uploads without checks can be misused.

Here are the main things to watch.

Restrict file types

Do not accept every file type blindly. For example, if your app only needs images, reject anything that is not an image.

This matters because users could upload unsafe files or files that your app was never designed to handle.

Limit file size

Large files can slow down your server or fill your storage very quickly. A size limit protects your app from unnecessary load.

Rename uploaded files

Never trust the original filename alone. Different users may upload files with the same name. Also, some filenames may contain strange characters.

Adding a timestamp or unique ID to the filename helps avoid collisions.

Keep uploads organized

Do not dump every file into one large folder forever. Use separate folders when needed, such as images, documents, or avatars. This keeps the project easier to manage.

Do not expose sensitive files

Only serve files that are meant to be public. Some uploaded files should remain private and accessible only to logged in users.


A better folder structure

As your app grows, a more structured setup is easier to maintain.

This structure keeps things organized. Images stay in one folder, documents in another, and the codebase remains easier to read.


Conclusion

Handling uploaded files in Express becomes straightforward once you understand the flow clearly.

A file is received through a request, stored either locally or in external storage, and then made accessible through a URL using static file serving. Each step has a specific role, and together they form a complete system.

For smaller projects and learning, storing files locally and serving them using Express works well. As applications grow, moving to external storage becomes more reliable and scalable.

What matters most is not just storing files, but doing it in a structured and secure way. If you can manage uploads, organize storage, and safely serve files to users, you are building a strong backend foundation.

JavaScript Journey: From Basics to Core Concepts

Part 24 of 29

This series documents my journey of learning JavaScript and breaking down important concepts in a simple way. Each article covers a core JavaScript topic with clear explanations and beginner-friendly examples. From basic concepts to essential JavaScript features, the goal of this series is to make JavaScript easier to understand while practicing and sharing what I learn.

Up next

URL Parameters vs Query Strings in Express.js

When building real applications, URLs are not just addresses. They carry meaning and data. Two of the most common ways to pass data in a URL are URL parameters and query strings. At first glance, they