Serving Static Files with Node and Express.js

Introduction

In this article, we are going to a build simple app to serve static files like HTML files, CSS files, and images using Node.js and Express.

Configuring the Project and Installing Express

To get started, let's create a new Node.js project by running the init command in a new folder:

$ npm init

Fill the requested information to your requirements or just set the default values by leaving each line blank.

Now we can install the Express framework by running:

$ npm install --save express

We are all set, let's start coding!

Serving Files with Express

There are two ways to serve static files using Express:

  • Serving a single file by configuring a path to the resource
  • Setting a public directory in which all files are accessible

We'll go over each of these methods in the next two sections.

Serving a Single File

Consider a scenario when we want to create a simple landing page that consists of 3 HTML documents (home.html, contact.html, and about.html), and we want to serve these files to the user.

Let's assume that the user visits the root path (http://localhost:3000). In that case, we want to serve the home.html file. Similarly, if the user visits the /contacts or /about paths, we want to serve the contact.html and about.html files, respectively.

To implement this, let's create a landing-page.js file and import the Express library:

const express = require('express');

Then, we'll create the Express app:

const app = express();

Then let's define the port on which our server will be running, which we'll use later when we actually run the server:

const port = 3000;

Since we are sending a single file, we won't include links to any CSS or script files within those HTML files unless they are hosted in a different location, like a CDN, for example.

We'll handle serving these files together in the next section, so for now, let's stick with three very simple, bare-bone HTML files:

home.html:

<body>
    <h1>Home</h1>
</body>

contact.html:

<body>
    <h1>Contact</h1>
</body>

about.html:

<body>
    <h1>About Us</h1>
</body>

Now let's go back and edit our landing-page.js file to send files corresponding to the paths the user visits, such as sending the home.html file when the user visits the root path.

We can use the res.sendFile() method to serve a file within a response:

app.get('/', (req, res) => {
    res.sendFile('./landing-page/home.html', { root: __dirname });
});

For security reasons, it's best to use a static path for res.sendFile(), as shown above. If you're ever taking user input that affects the file path, be very careful to prevent the user from being able to manipulate the file path and thus allowing them to retrieve private files.

In our case, we're setting the root for where the relative path is from by passing the root parameter to the method. Note that, we have passed __dirname, which is a Node.js global variable to the path of currently running file.

We can use the same method to serve our other files, contact.html and about.html, as well:

app.get('/about', (req, res) => {
    res.sendFile('./landing-page/about.html', { root: __dirname });
});

app.get('/contact', (req, res) => {
    res.sendFile('./landing-page/contact.html', { root: __dirname });
});

Now that our application is ready to go, let's start the server and listen to the port we set earlier:

app.listen(port, () => console.log(`listening on port ${port}!`));

And run our app by executing:

$ node landing-page.js

Open your browser and visit any of the mapped paths and you should be greeted with the HTML file(s):

Setting up a Public Directory

The second method of serving static files is to set up a public directory. Unlike sending a file through the HTTP response, where only a single file can be served, all files inside our specified folder will be available for users.

Let's create another file, called server.js, and set the folder with our three HTML documents to be a public directory:

const express = require('express');
const app = express();
const port = 3000;

// Setting up the public directory
app.use(express.static('landing-page'));

app.listen(port, () => console.log(`listening on port ${port}!`));

Making a directory public is as easy as using the app.use() and express.static() methods.

Let's run our app again and verify that it's working:

$ node server.js

Open your browser and visit any of the mapped paths and you should be greeted with the HTML files, just like last time. Keep in mind that this time, the root path is not mapped to the home.html file, but rather the http://localhost:3000/home.html:

Also, you can set a prefix to the path to access your public directory by passing the prefix as the first parameter:

app.use('/public', express.static('landing-page'));

Now, the files are situated on another path. For an example, home.html is now located at http://localhost:3000/public/home.html.

Unlike the first method where you'd hit /about and about.html would be served, note that you have to use the full file name in order to retrieve the file here - /about.html, for an example.

This allows us to host other files such as CSS, JavaScript files, and images as well.

For example, if there is a cat image on your public folder called cat.png, the server will be serving it on http://localhost:3000/public/cat.png depending on your configuration and you can easily call it via an HTML page and display it.

If you are planning to host a landing page like this, most probably it could be a combination of both methods that we discussed above. You can use a response to send a single HTML file and a public directory to host other static assets such as CSS files, JS scripts, and images.

Conclusion

The source code of this project is available on GitHub as usual. Use this to compare your code if you ever got stuck along the tutorial.

Happy Coding!

Author image
About Janith Kasun
Colombo, Sri Lanka Twitter