Express is a popular web framework that helps us create a node js web app with minimum configuration.
In the previous post, we learned the basics of node js, npm, and how to create a simple web server with the help of node js.
In this article, we will learn how to create a simple static web app with the help of the express web framework.
Table of Contents
- Creating the hello world node js app with express js
- Creating a static web app with express
- Running the static app
- Conclusion
Creating the hello world node js app with express js
Create a directory with the name express-static-app, navigate inside the directory and run the command npm init.

Create an index.js file in the current directory. This file is the entry point of the application.
Next, we will install the required node js libraries to our application.
Installing the express package
To add the express package, run the command npm i express -s.

This will install the express package into our application as a dependency.
Now, we can start using the express package to create a simple web server.
Update the index.js file with the below content.
const port = 3000, express = require("express"); app = express(); app.get("/", (req, res) => { console.log(`request recieved at:${req.url}`); res.send("Hello Universe!"); }); app.listen(port, () => { console.log(`The Express.js server has started and is listening on port number: ${port}`); });
- We have imported the express js package and initiated it.
- The get() function of the express framework helps to handle incoming HTTP GET requests.
- The configuration on line number 6 handles the HTTP requests made to the URL /.
- We are calling the listen() function and passing the port number that the application should use.
Start the application by executing the command node index.js
Access the application using a web browser at http://localhost:3000.

We can also observe that the application runs on port number 3000, and the express framework handles the incoming user request.

Building routes using express
Next, we will create the URL routes that serves the content for our application.
Creating controller layer
Create a directory called controllers under the base directory of the application and create a staticAppController.js file.
We will segregate the request handling into this file to keep the application structured.
exports.hello = (req, res) => { console.log(`request recieved at:${req.url}`); res.send("Hello Universe!"); }
We have moved the existing logic of the app that we have created earlier to a new file.
Now we can import the controller file in the index.js file, as shown below.
const staticAppController = require("./controllers/staticAppController"); app.get("/", staticAppController.hello);
Start the application. If everything is fine, we should get the same screen with “Hello Universe”.
Creating a static web app with express
So far, we have learned how easy it is to work with express js.
In this section, we will create a static web app. We will also learn how to handle POST requests, serving the static files, error handling, etc.
We will also configure the bootstrap CSS support.
Setting up the application
Install the bootstrap package by executing the command npm i bootstrap -s.

Install the EJS package by executing the command npm install ejs -s.

Embedded JavaScript(EJS) helps us to apply the javascript functions and variables within our views. EJS view files have .ejs the extension.
Finally, install the ejs-layouts package by executing the command npm install express-ejs-layouts -s.

Layouts help us create a fixed layout shared across the application. For example, We can display the same header and footer content across the application pages.
Create the required files and folders
Let us create the required views, public files controllers, etc.
Views
Create a folder with the name views under the application’s home directory.
The EJS library uses this folder to render the appropriate views.
Create a file called index.ejs and add the the below content.
<main role="main" class="container"> <h1 class="mt-5">My Website</h1> <h2>My subscribers list</h2> <table class="table"> <thead> <tr> <th scope="col">Name</th> <th scope="col">Email</th> </tr> </thead> <tbody> <% mySubscribers.forEach(subscriber=> { %> <tr> <td> <%= subscriber.name %> </td> <td> <%= subscriber.email %> </td> </tr> <% }); %> </table> </table> </main>
- The index.ejs file is our home page of the static web application. We display the subscribed user details on this page.
- The lines highlighted above show that how EJS is helpful to add the javascript functions and access javascript variables inside the view pages.
Similarly, Create a subscribe.ejs and thankyou.ejs files in the same directory.
<main role="main" class="container"> <h1 class="mt-5">Subscribe to my website</h1> <div> <form action="/subscribe" method="post"> <input type="text" name="name" placeholder="Name"> <input type="text" name="email" placeholder="Email"> <input type="submit" name="submit"> </form> </div> </main>
The below is the thankyou.ejs file.
<main role="main" class="container"> <h1 class="mt-5">Thank you for subscribing to my web site</h1> </main>
The subscribe.ejs view file is used to capture the user details and after successful submission, a thank you message is displayed to the user.
Creating the view layout
As we have added the ejs-layouts package to our application, we can use this to create a fixed page structure across all application pages.
Create a new folder called partials under the views folder and create new file navigation.ejs.
<header> <nav class="navbar navbar-expand-md navbar-dark fixed-top bg-dark"> <ul class="navbar-nav mr-auto"> <li class="nav-item active"> <a class="nav-link" href="/">Home</span></a> </li> <li class="nav-item"> <a class="nav-link" href="/subscribe">Subscribe</a> </li> </ul> </nav> </header>
Create a layout.js file and add the below content.
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <title>My express app</title> <link href="./css/bootstrap.css" rel="stylesheet" type="text/css"> </head> <body data-new-gr-c-s-check-loaded="14.1018.0" data-gr-ext-installed=""> <%- include('partials/navigation') %> <%- body %> <script src="./js/bootstrap.js" type="text/javascript"></script> </body> </html>
- We have the complete HTML structure in this view with html, header, and body tags.
- We are importing the bootstrap CSS on line number 7 and bootstrap JS file on line number 13 in this layout file, as it will be available across the application pages.
- Line number 11 shows how to import a partial view like a navigation bar.
- Line number 12 inserts the currently rendered view content to this location.
- The layout.js file of our application will display a consistent navigation bar across all pages of our application. These pages can be either index.ejs, subscribe.ejs or thankyou.ejs in our example.
Creating a static error page
Create a folder with the name public and add an error.html file as shown below.
The page displays an error message for errors like page not found(404), etc.
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <title>My express app</title> <link href="../css/bootstrap.css" rel="stylesheet" type="text/css"> </head> <body> <div class="alert alert-danger" role="alert"> Opps!! something went wrong!! </div> </body> </html>
Wiring it all together
We have set up all the required page and layout views in the previous section.
Now we will create the required controller layer to handle the requests made on different URLs and serve appropriate views.
Finally, we will modify the index.js file by adding necessary package imports and configuration to use EJS and express-layouts packages and custom controllers.
The controller layer
We will modify the existing staticAppContoller.js file and add a new controller js file to handle the application errors.
The main controller
Update the staticAppController.js file with the below content.
const subscribers = []; exports.getHomePage = (req, res) => { res.render("index", { mySubscribers: subscribers }); } exports.getSubscribePage = (req, res) => { res.render("subscribe"); } exports.saveSubscriber = (req, res) => { subscribers.push(req.body); res.render("thankyou"); }
- The “subscribers” array holds the subscriber list of our application.
- The “getHomePage” function renders the index.ejs file and also adds the subscriber list to the response.
- The “getSubscriberPage” function renders the subscribe page.
- The “saveSubscriber” function adds the subscriber data submitted by the user into the existing subscriber list.
Handling error on node js express application
Let us create an errorController.js controller file that handles the HTTP 404 or 500 errors.
exports.pageNotFoundError = (req, res) => { res.redirect('/html/error.html'); }; exports.internalServerError = (error, req, res, next) => { console.log(`ERROR occurred: ${error.stack}`); res.redirect('/html/error.html'); };
- If the defined request handlers are not handling the incoming request on a specific path, the application invokes the function pageNotFoundError.
- The application invokes the internalServerError function if any application error occurs during runtime, and the browser renders a static error page.
Updating the index.js file
Update the index.js file with below content.
const port = 3000, express = require("express") layouts = require("express-ejs-layouts"); app = express(); const path = require('path'); app.use('/css', express.static(path.join(__dirname, 'node_modules/bootstrap/dist/css'))) app.use('/js', express.static(path.join(__dirname, 'node_modules/bootstrap/dist/js'))) app.use('/js', express.static(path.join(__dirname, 'node_modules/jquery/dist'))) app.use('/html', express.static('./public')) app.set("view engine", "ejs"); app.use(layouts); //Parse URL encoded data and use JSON format. app.use(express.urlencoded({ extended: false })); app.use(express.json()); const staticAppController = require("./controllers/staticAppController"); const errorController = require("./controllers/errorController"); app.get("/", staticAppController.getHomePage); app.get("/subscribe", staticAppController.getSubscribePage); app.post("/subscribe", staticAppController.saveSubscriber); app.use(errorController.pageNotFoundError); app.use(errorController.internalServerError); app.listen(port, () => { console.log(`The Express.js server has started and is listening on port number: ${port}`); });
- We have imported the “express-ejs-layouts” package that enables EJS layout support to our application.
- We have configured the static file paths and this includes bootstrap file directories and the public directory that we have added under earlier.
- The app.set(“view engine”, “ejs”) configures EJS as the view engine of the application.
- Also, we have added the imported layouts package to enable the view layout support.
- The line number 17 and 18 enables the parsing of the URL encoded data into the JSON format.
- We also have imported the controllers, that are responsible for rendering the views or processing the data submitted by the user.
- Finally, we have configured the application to use the error controller methods that are defined in the errorController.js file.
Running the static app
To run the application, we can use the command node index.js.
We can also add a start script to the package.json file and launch the application by executing the “npm start” command.
{ ... "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "start" : "node index.js" }, ... }
Initially, the home page will have empty subscribers list, as shown below.

Click on the Subscribe link on the navigation bar, enter the details and submit the form.

A successful message is displayed after user submits the form.

Navigate back to the Home page. The page displays the subscribers list on the screen.

Try to access a random URL, and the page redirects to the error page.

Conclusion
In this article, we learned how to create a simple node js web app with the help of the express framework.
We also added bootstrap css and added some custom styling to our application.
We also learned how to serve the ejs files and display data using the express-ejs-layout package.
The code is available on Github.