Set up a Node / Express Static Web Server in Five Minutes


node express static web server

Setting up Node and Express as a Simple Lightweight Web Server for Your Single Page Application is Very Easy to Do.

Sometimes you just need a local web server.  Sure, you could use MAMP, but installing Apache, MySQL and PHP seems like overkill in some cases. I have used MAMP for years and it is terrific. In particular, when you need to run PHP locally and / or connect to a MySQL database, it’s the cats pajamas. But that was the standard 10 years ago. Nowadays, it’s very common to build a single page web application where all of the assets are static, data is pulled-in from a REST endpoint and all of the heavy lifting is done in the browser via JavaScript. In these kinds of scenarios, a static Node / Express server is a simple, easy and lightweight approach.

In this article I’ll explain the steps needed to set up a Node / Express Static Web Server. And the good news is that on this high level, the required steps are very simple. First, you’ll need to require the express and path modules. After that, you’ll create an instance of express, then set the port that the web-server will use. The next step, and the key-ingredient here is the express.static method. This tells Express.js that you want to serve static content from a specific folder. In that one line of code, you’ve done the majority of the configuration work.

So, not only will Express serve-up static content from that folder, it can do so for any subfolders as well. You can specify any folder in your project as the static web folder. And the beauty of it is that any folder outside of the one you specify will be hidden from public view, so your application code will be safe. When you pass the the express.static method to the use method of your express instance, you provide the details that express needs to serve your static content. Then finally, you use the listen method of your express instance to start the web server. We’ll take a closer look at the express.static method in Example # 2.

Now, I just want to remind you here that this article pertains to the specific occasions in which you need to serve static web assets locally. In other words, using a Node / Express static web server can be a very simple way to satisfy your need for a local web server, but may not be the best approach for your production needs. Technically, you could take the code that is detailed in this article and deploy it to your production server, and in theory it would work just fine. For this article, however, I’m just going to concentrate on providing a fast and simple way to get a local web server running so that you can test your front-end code (e.g. HTML, CSS or JavaScript).

The code samples can be downloaded here:

Example # 1 – package.json

In Example # 1, we have the contents of package.json. Nothing too special going on here. But just note that our only dependency is the express module. Also, in the scripts property, I’ve set up the start command to execute the app.js file in the node web-server folder. This way, we can simply type npm start in the terminal, instead of node web-server/app.js (just a bit less typing).

Example # 2 – The Express Static Web Server

In Example # 2, we have the entire contents of our web server: 15 lines of code (and nearly 25% of that is comments!). The magic happens on line # 10:  We call the app.use method and pass it express.static, which also takes a couple of arguments. So this tells Express that we want to set a static folder. We then use the path.join method to tell Express where all static assets should be served from. In our case, it is the www folder. The two arguments passed to the path.join method are __dirname, which tells us the absolute path to the folder within which the current script is found, and then “../www” which is a relative path to the www folder.

Now, as I mentioned earlier, anything outside of your static folder is protected from public view. This means that while the folder you specify when calling the express.static() method (i.e. “../www”) is publically viewable, any folder that is a sibling or descendant of that folder is not available publically. This is not a critical factor when working locally (i.e, developing), but it does matter in production. In other words, you wouldn’t want your application code to be viewable to the general public. Nor would you want to make available any sensitive information that’s in your application code, such as a secret key or other credentials. So, as you can see, this is one of the key strengths of Express, which is the ability that it provides you to not only define your public/static folder in one line of code, but to also protect all of the other folders by default.

Express does all of the heavy lifting

A little earlier, I used the word magic. We both know that none of this is actually magic, but it sure feels like it. If you’ve ever created a Node web server manually, then you know two things: 1) It’s really easy, 2) It’s really tedious once you get past “Hello World”.  But Express hides all the tedium and makes serving static assets as easy as 1-2-3.

HTTP Headers

There is one downside here. Express does not set the appropriate content-type headers for the HTTP requests.  This is not fatal in most cases because this approach is simply meant to provide a very fast and easy way to set up a static web server. The actual web server works just fine, but keep in mind that content-type headers for files such as JPEG, PNG, CSS or JS will not be set accordingly. If that is a problem, then a simple static web server is probably not what you need and you should consider a more robust approach. So, hopefully, if you do need a simple static web server, this article was what you needed to get up and running quickly.


There are multiple options when it comes to setting up a static web server. One advantage to leveraging Node and Express.js, however, is that as a developer, you probably already have Node installed on your machine. So, in this case, you won’t need to install any additional software. You can simply import the Express framework, write about a dozen lines of code, and you have a static web server. This is probably not a server that you would use in production, but as you can see, it can easily solve the problem of quickly serving web content on your local machine. If you need to write moderately complex dynamic application logic, then you might need something a bit more advanced than what was discussed here. But for a basic static web server, this approach should get you going (hopefully in less than five minutes : – )

Making a Simple HTTP Server with Node.js – Part IV


Node.js Logo

Setting the right value for the “Content-Type” header is a critical task for any web server

In Part III of this series, we built out our Node.js server to serve up any file that is requested, or gracefully return a 404 / “Not Found” header, as well as a custom HTML page informing the user that the requested file was not found. But the only problem is that we are not setting headers for each request. So, it’s important that HTML, CSS, JavaScript and image file, have the appropriate “Content-Type” header set.

In order to demonstrate all of this, we will include a CSS file and a JavaScript file in our web page. I won’t bother including the CSS file in an example; it’s just some silly CSS… nothing too interesting. But I will include the source of our JavaScript file in Example # 1, just so we can see that the second blue box in the web page is created via JavaScript.


Example # 1

Example # 1 simply shows the contents of the JavaScript file: “script.js” that we will request in our pages.

Example # 2

Example # 2 is the source code for index.html.

Example # 3

Example # 3 is the source code for about.html, a second web page that we can request from our Node.js web server.

Before we go any further, let’s take a  moment to discuss the folder structure. Just as in Part III of this series, the folder that our server.js file sits in has a sub-folder named “public”. This is where our assets will go. It is this “public” folder that the world will have access to and all requested files will be in there. See Figure # 1.

Folder structure
Figiure 1: The folder structure for this article’s example.

Example # 4

In Example # 4, we have a JavaScript object that contains a list of mime-types that we will support. Each of the object’s properties represents a file extension that we plan to support, and the corresponding value is the mime-type string that will be used for the “Content-Type” header.

Example # 5

In Example # 5, we have added a new line to the variable declarations for the requestHandler() function. The variable “ext” contains a string copy of the requested file’s extension (e.g. “.html” for a web page, “.js” for a JavaScript file, and so on). So we will use that string to check all properties of the “extensions” object from Example # 4. Don’t worry if you feel like you are getting lost; we’ll piece everything together nicely at the end. For now, just know that we have so far provided a hard-coded list of file extensions that we will allow, and the mime-type string values for each one, and we have the variable: “ext” that tells us what the file type is.

Example # 6

In Example # 6, we see if the extensions object has a property that matches the value of the “ext” variable. If not, we write a 404 header, and return a simple HTML page, informing the user that the requested file type is not supported.

Example # 7

In Example # 7, we add a new argument to the getFile() function call. We pass-in the value of the property in the extensions object that matches the file extension of the user’s request. In a nutshell, we are telling the getFile() function what type of mime-type to set in the response header.

Example # 8

In Example # 8, we have expanded the res.writeHead() function call. Where previously we only set the 200 / “OK” response code, we now set the “Content-Type” and “Content-Length” headers. The “Content-Type” property is mapped to the value of the mimeType variable, which was passed-in as an argument to the function. So the fruits of our labor in this article all become apparent in this example. The value of the mimeType variable will be set accordingly, for the file type.

Example # 9

Example # 9 is a complete code-listing for this article. In Figure # 2, we see the results of http://localhost:3000/index.html. So, as you can see, we are serving not only HTML, but also an image file, a CSS file and a JavaScript file. The JavaScript file dynamically creates the blue box you see on page load (simply to demonstrate that our JavaScript file is served correctly from our Node.js web server, and works).

index.html page
Figure # 2: Our index.html page.

In Figure # 3, we see that our “about.html” page works, and also pulls in the CSS and JavaScript files with no problems.

Figure # 3: about.html

In Figure # 4, we inspect the JavaScript file call in the “net” tab of FireBug and can see that the “Content-Type” header is set accordingly.

The FireBug
Figure # 4: Inspecting the call to script.js in FireBug’s “net” panel


In this article we learned how to set the appropriate “Content-Type” header for each request, based on the file extension of the requested file. We demonstrated how to use the extname() method of the path module, to return the extension of the requested file. We also applied some logic, to handle scenarios in which the requested file-type is not supported.

Helpful Links for the Node.js path module

Helpful Links for HTTP header fields

Helpful Links for mime-types

Making a Simple HTTP Server with Node.js – Part III


Node.js LogoIn Part II of this series: Making a Simple HTTP Server with Node.js – Part II we learned how to use the “path” and “file system” modules. By leveraging these Node.js modules, we were able to read the path of the HTTP request that our server received, and read from the file system of the web server. We also learned about the “__dirname” keyword, which provides an abstract reference to the folder in which the currently executing JavaScript file exists.

That version of our HTTP server simply checked to see if the request was for the file “index.html”, and if so, served it up. That was progress over Part I, but still not robust enough.

In this article, we will expand our Node.js HTTP server so that the following services are provided:

  • If an asset is requested, and it exists, it will be returned
  • If an asset is not specified, then “index.html” will be returned
  • If an asset is requested, and it does not exist, our custom 404.html page will be returned

We will make every effort to keep our three-step paradigm, which will, we hope, continue to illustrate that creating an HTTP web server with Node.js is at its core, quite simple. What we have to take a closer look at, is the fact that, as we ask more of our little web server, we have to roll up our sleeves and write the code that provides that very functionality.

So the good news is: It’s just more JavaScript. Yay!

Example # 1

In Example #1, we have the three-step core of our HTTP web server. We have already discussed each step in detail, so let’s just quickly re-cap:

Step # 1: Use the require() method to gain access to the Node.js modules that we need
Step # 2: Use the createServer() method of the HTTP module, and pass it a reference to our “requestHandler” function
Step # 3: Listen for a request on port # 3000

Simple, simple, simple.

Next, let’s look at two functions: our updated requestHandler() function, and then our new getFile() function.

Example # 2

In Example # 2, we first look at the request, and if no file was requested (i.e. the user simply typed into their browser), then we prepare to serve up “index.html”.

As we learned in Part II, the __dirname keyword provides an abstract reference to the folder in which the currently executing JavaScript file resides. We then create a variable named “page404”, which will provide a reference to our custom “404 / Not Found” page, should we need it.

Now we have everything we need, so we call the getFile() function, passing it the path and name of the asset we want (i.d. index.html), the response object, and then the reference to our custom 404 page.

Example # 3

In Example # 3, there are some new things happening. First, we use the exists() method of the file system object that was returned by the “fs” module, and assigned to our variable: “fs”. This method takes two arguments: a path to the file, and an anonymous function. That anonymous function takes one argument: “exists” (call it whatever you like). That single argument provides a helpful “truthy/falsy” flag against which we can test.

Folder Structure
The folder structure of this article’s example code

So if you take a moment to think about this, you’ll find that it’s quite cool: baked into the Node.js “fs” module is a method that simply tells us whether or not a named file exists. This is a perfect example of the brilliance of Node.js modules. Imagine how much heavy lifting you’d have to do if you needed to provide this kind of implementation yourself. Fortunately, someone did it for you. And that module can be used over and over again… a zillion more times if you like.

So moving along, if the “exists” argument returns a “truthy” value, we use the fs.readFile() method to literally read the physical file from the local file system. We have a little error checking to make sure that the file read operation did not fail, and if it did not fail, we send the contents of that file back to the user.

If the requested file was not found (i.e. the “exists()” method told us that the named file does not exist), then we serve up the custom 404.html file that we still have a reference to.

Example # 4

Example # 4 simply puts all our code examples together, to provide some context.


In this article we expanded our simple Node.js HTTP web server. We leveraged the exists() method of the “fs” (file system) object, to determine if the requested file actually exists, and provided logic that handles cases in which the requested file does not exist.

Helpful Links for the Node.js path and fs Modules

Making a Simple HTTP Server with Node.js – Part II


Node.js Logo

OK, enough “Hello World!” Let’s serve up an HTML file, dagnabbit.

In Part I of this series: “Making a Simple HTTP Server with Node.js – Part I“, we learned the bare-bones steps needed to create an HTTP server with Node.js. While it was fun to see our text message make its way from our server-side JavaScript file, at the end of the day we sent a hard-coded text message. Not too sexy.

In this article, we will invite the user to type “index.html” into their browser window and prepare to be amazed. Ok, the user has to be on your local DEV machine, and type “http://localhost:3000/index.html”, but we have to start somewhere, right?

Example # 1

There are a few new things happening in Example # 1, when compared to the examples from Part I of this series. The biggest change is that we’ve expanded “Step # 1” and are requiring two new Node.js modules: “path” and “fs”.

The “path” module provides a number of methods that help you to examine and parse file paths. The “fs” module is short for “File System”. This module provides access to the file system. So here is where the fun stuff starts: Writing JavaScript that has access to the local file system? Yep. You bet. We have not even begun to scratch the surface of what is possible.

Next, our helper function has grown a bit as well. We use the basename() method of the path module to return the name of the file that was requested by the user (i.e. index.html). We then leverage the “__dirname” keyword, which provides a quick and easy handle to the folder that your server-side JavaScript file resides in.

After that, we check to see if the user has requested “index.html”, and if so we will return it. The fs.fileRead() method takes two arguments: a path to the physical file that we want to return to the user, and an anonymous function. That anonymous function takes two arguments: an error object, and the content of the file that is to be returned. So just to play it safe, we check to see if there is an error: if ( !err ). If there is none, then we use the res.end() method to return the contents of index.html and then close the request. If there was an error, for now we are piping it to the console for our own troubleshooting.

If none of that worked out, then we set a “404 / Not Found” header, and send some markup back, letting the user know. Step # 2 and Step # 3 haven’t changed since our last article: Create the server, and then listen for a request.


That was a lot, but our Node.js HTTP server has grown up quite a bit. Instead of just sending back a plain text message or some hard-coded HTML, we are now serving up an actual HTML file. We could change that file any time, which would change what the user sees in the browser. It’s not exactly Facebook, but hey, we are creating an HTTP web server using nothing but JavaScript!

For Part III, we will smarten things up and enhance our server so that it will serve up any static content that is requested.


In this article we learned how to use the “path” and “file system” Node.js modules. By leveraging the modules, we were able to read the path of the HTTP request, and read from the file system. We also learned about the “__dirname” keyword.

Helpful Links for the Node.js path and fs Modules

Making a Simple HTTP Server with Node.js – Part I


Node.js LogoThe beauty of creating an HTTP server with Node.js is that you are doing so using a language that you already know: JavaScript.

If you work with JavaScript, then you’ve probably heard about Node.js. What makes Node.js such an amazing technology is that it turns web-development on its head: a historically client-side language is now being used as a server-side language. I’m sure I don’t have to tell you how insanely cool this is.

When I first started looking at Node.js, my first question was: “Ok, server-side JavaScript. Got it. So what the heck can I do with it?”

Short answer: A lot.

Probably the most obvious and easiest to comprehend application for Node.js is to make a web server. Node handles all the low-level ugliness and let’s you just write code. The code you write is not too much different than the client-side JavaScript that you are used to. The biggest differences come in when you start to realize that you have access to the file system. You can do things with Node that are completely off-limits on the client side. When it comes to creating a simple HTTP server, the amount of code you need to write for proof of concept is amazingly minimal. The examples that follow are very basic. They don’t offer any real-world usefulness, but they do illustrate the small amount of effort needed to get up and running. In Part II of this series, we will look at more realistic HTTP server code for Node.js.

Example # 1 A

In Example # 1, we have the absolute bare minimum needed to set up an HTTP web server using Node.js. The very first line tells Node.js that we need to use the “http” module. Using Node’s “require” method, we assign the return value of the “HTTP” module to the variable “http”. This was Step # 1.

(A detailed discussion of the require() method is beyond the scope of this article, but a topic that plays an important role in Node.js. If you are not familiar with the Modules/AsynchronousDefinition proposal from Common.js, I highly recommend reading up on that topic. For any client or server-side JavaScript developer, it’s a biggie.)

The only part that might seem a bit confusing to some is the callback that is passed into the createServer() method. This callback is executed each time the server receives an HTTP request.

For Step # 2, we call the createServer() method of the http object. We pass that method an anonymous function which takes two arguments: the request object and the response object. Inside of that anonymous function, we use the writeHead() method of the response object, to set the server’s response of “200 ok” to the client’s browser, and set the header of “Content-type” to “text/plain”. Next, we call the end() method of the response object. The end() method closes the response to the client. It can also send output to the client. We pass in a string as an argument in this example, and that string is sent to the client’s browser.

For Step # 3, we call the listen() method on the return value of the createServer() method. We pass in “3000”, which tells Node.js to listen on port # 3000.

If you run this code in Node.js, and then in your browser, “type localhost:3000”, you will see the following in your browser: “Your node.js server is running on localhost:3000.”

Whew! The explanation for Example # 1A took much longer to write than the actual code!

As you can see, it’s pretty easy to create an HTTP server with Node.js. In my opinion, the only part that might seem a bit confusing to some is the callback that is passed into the createServer() method. This callback is executed each time the server receives an HTTP request. It might make things easier to understand if we move the guts of that callback to its own function, and then pass that function declaration as the callback to the createServer() method.

Example # 1 B

In Example # 1B, we create a function declaration named requestHandler. Then we pass that function as the sole argument to the createServer() method. I believe that if you are new to Node.js, you’ll find it is easier to see what is going on, because the createServer() method is all on one line.

Example # 1 C

In Example # 1C, we’ve refactored our code to make things even simpler. First, our helper function processes the HTTP request, then Step 1, Step 2 and Step 3. Bing, Bang, Boom. Simple stuff.

Example # 2 A


In Example # 2A, we’ve upgraded our message to the client’s browser to include some HTML. After all, HTML is what we will really want to serve, right? The only problem is that Node is not parsing the HTML. When you run this example in your browser, you see the HTML tags in the response. That is not what we want. What is happening?

The problem is in the header that we are setting with the res.writeHead() method call. The value of the “Content-Type” header is “text/plain”. So, Node just passes all the text along as… well, plain old text.

Example # 2 B

In Example # 2B, we have changed the value of the “Content-Type” header to “text/html”. If you run this example in your browser, you will see that Node sends the string as HTML, so our H1 and UL elements are rendering as they should in the browser.

Example # 3

In Example # 3, we take things a bit further. Up until now, we have been using the res.end() method to do two things: send some text or HTML to the client’s browser, and then close the response. In this example, we use the res.write() method to send our HTML to the client’s browser, and the end() method is used only to close the request.

We’ve also introduced some logic into our code. While what this example accomplishes is very little, and has virtually no real-world value, it demonstrates that while we have created an HTTP server, we have done so with JavaScript, and we already know the JavaScript language. So, we can do something like create a for/loop block, and use that loop to provide some dynamic HTML output. Again, this “dynamic” aspect of our code is not very impressive, but I think you get the point: it’s just JavaScript, so the sky’s the limit.


In this article, we learned how to create a simple HTTP server using Node.JS. We covered the three most basic steps needed, which include requiring the HTTP module, calling the createServer() method, and then telling the server to listen for an HTTP request. Finally, we learned how the server executes a callback function for each HTTP request it receives, and the most basic things that need to happen inside of that callback.

Helpful Links for creating a simple Node.js HTTP Server