Expressjs Serving Static Files and Templating ejs pug Step by step Implementation and Top 10 Questions and Answers
 Last Update:6/1/2025 12:00:00 AM     .NET School AI Teacher - SELECT ANY TEXT TO EXPLANATION.    13 mins read      Difficulty-Level: beginner

Express.js: Serving Static Files and Templating with EJS and Pug

Express.js is a minimal and flexible Node.js web application framework that provides a robust set of features for web and mobile applications. One of the key capabilities it offers is serving static files and handling templating, allowing for dynamic web content generation. In this article, we'll delve into each component by exploring how to serve static files and work with two popular templating engines: EJS and Pug.

Serving Static Files

Static files such as images, CSS, and JavaScript files are essential for proper rendering and user interaction on a web page. In Express.js, serving these files efficiently can be accomplished using the built-in middleware express.static.

Setting Up express.static

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

// Serve static files from the 'public' directory
app.use(express.static('public'));

app.listen(3000, () => {
  console.log('Server is running on http://localhost:3000');
});

In the above example, any files stored in the public directory (e.g., public/images/logo.png, public/css/style.css) can be accessed directly via URLs like http://localhost:3000/images/logo.png or http://localhost:3000/css/style.css.

Serving Multiple Directories

If you need to serve files from multiple directories, simply call express.static multiple times.

// Serve static files from 'public' and 'assets' directories
app.use(express.static('public'));
app.use(express.static('assets'));

Using Absolute Paths

You can also serve files from an absolute path if needed.

app.use(express.static(__dirname + '/public'));

Customizing the Static Cache Control

To improve performance, you can customize the cache control headers sent to clients.

app.use(express.static('public', {
  maxAge: '1d' // Cache files for one day in the browser
}));

EJS Templating Engine

EJS (Embedded JavaScript Templates) is a simple and unopinionated templating language for generating HTML markup with plain JavaScript. EJS extends HTML with templating capabilities, making it an easy-to-use choice for dynamic content.

Setting Up EJS

First, install EJS via npm.

npm install ejs

Next, configure Express.js to use EJS as the templating engine.

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

// Set EJS as the templating engine
app.set('view engine', 'ejs');

app.get('/', (req, res) => {
  res.render('index', { title: 'Welcome', message: 'Hello World!' });
});

app.listen(3000, () => {
  console.log('Server is running on http://localhost:3000');
});

Creating EJS Templates

Create an index.ejs file in the views directory.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title><%= title %></title>
</head>
<body>
    <h1><%= message %></h1>
</body>
</html>

In the template, <%= title %> and <%= message %> are placeholders that will be replaced with the values passed from the res.render method.

EJS Tags

EJS provides several types of tags to include dynamic content and logic in templates:

  • <%= %>: Outputs the escaped HTML.
  • <%- %>: Outputs the unescaped HTML.
  • <% %>: Executes the JavaScript code.
  • <%# %>: Comment block.
  • <%%>: Outputs a literal <%.
  • <%_ %>: Whitespace-trimmed code block.
  • <%-_%>: Whitespace-trimmed unescaped code block.

Example with Conditionals and Loops

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title><%= title %></title>
</head>
<body>
    <h1><%= message %></h1>
    <ul>
        <% users.forEach(user => { %>
            <li><%= user.name %> - <%= user.email %></li>
        <% }) %>
    </ul>
</body>
</html>

In the Express route:

app.get('/', (req, res) => {
  const users = [
    { name: 'John Doe', email: 'john@example.com' },
    { name: 'Jane Smith', email: 'jane@example.com' }
  ];
  res.render('index', { title: 'Welcome', message: 'Hello World!', users: users });
});

Pug Templating Engine

Pug (formerly known as Jade) is a high-performance templating engine for Node.js that simplifies HTML creation by allowing for a more concise syntax. It generates HTML from the template files, enabling you to write HTML in a cleaner and simpler manner.

Setting Up Pug

Start by installing Pug.

npm install pug

Next, configure Express.js to use Pug as the templating engine.

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

// Set Pug as the templating engine
app.set('view engine', 'pug');

app.get('/', (req, res) => {
  res.render('index', { title: 'Welcome', message: 'Hello World!' });
});

app.listen(3000, () => {
  console.log('Server is running on http://localhost:3000');
});

Creating Pug Templates

Create an index.pug file in the views directory.

doctype html
html(lang="en")
  head
    meta(charset="UTF-8")
    meta(name="viewport" content="width=device-width, initial-scale=1.0")
    title= title
  body
    h1= message

In the template, title= title and h1= message are placeholders that will be replaced with the values passed from the res.render method.

Pug Tags and Syntax

Pug syntax eliminates the need for closing tags and indentation has a significant meaning, which makes it more concise and easier to read.

Conditional Statements

doctype html
html(lang="en")
  head
    meta(charset="UTF-8")
    meta(name="viewport" content="width=device-width, initial-scale=1.0")
    title #{title}
  body
    if message
      h1 #{message}
    else
      h1 No Message

Loops

doctype html
html(lang="en")
  head
    meta(charset="UTF-8")
    meta(name="viewport" content="width=device-width, initial-scale=1.0")
    title #{title}
  body
    ul
      each user in users
        li #{user.name} - #{user.email}

In the Express route:

app.get('/', (req, res) => {
  const users = [
    { name: 'John Doe', email: 'john@example.com' },
    { name: 'Jane Smith', email: 'jane@example.com' }
  ];
  res.render('index', { title: 'Welcome', message: 'Hello World!', users: users });
});

Conclusion

Express.js provides built-in support for serving static files and offers flexibility in choosing templating engines. We covered how to use express.static to serve static files and explored the basics of both EJS and Pug templating engines. By incorporating these features into your Express.js applications, you can create dynamic and visually appealing web pages efficiently.




Examples: Setting Route, Running Application, and Data Flow with Express.js for Serving Static Files and Templating (EJS & Pug)

Express.js is a powerful Node.js framework that simplifies the process of web development by providing a robust set of features to handle server-side logic efficiently. One of these features includes serving static files (such as images, CSS, and JavaScript) and using template engines like EJS or Pug to render dynamic content. Let's walk through an example step-by-step to understand how to implement these features.


Step 1: Setting Up Your Project

First, you need to initialize a new Node.js project. Open your terminal and run the following commands to create a new directory, navigate into it, and initialize your project:

mkdir express-static-templates
cd express-static-templates
npm init -y

This will create a package.json file with default values.


Step 2: Installing Required Packages

You will need to install express, ejs, and pug. Run the following command to install these packages:

npm install express ejs pug

Step 3: Creating the Server File

Create a new file named server.js in your project directory. This file will contain the setup for the Express server.

const express = require('express');
const path = require('path');

// Create an Express application
const app = express();

// Define port number
const PORT = 3000;

// Set path for static files (like images, css, js)
app.use(express.static(path.join(__dirname, 'public')));

// Set the view engine to EJS
app.set('view engine', 'ejs');
app.set('views', path.join(__dirname, 'views/ejs'));

// Optionally, set the view engine to Pug
// app.set('view engine', 'pug');
// app.set('views', path.join(__dirname, 'views/pug'));

// Start the server
app.listen(PORT, () => {
    console.log(`Server is running on http://localhost:${PORT}`);
});

In this example, we've set up Express to serve static files from the public directory and use EJS as the templating engine. If you prefer using Pug, you can uncomment the Pug configuration lines and comment out the EJS lines.


Step 4: Adding Static Files

Create a public directory at the root level of your project. Inside public, add some static files, such as CSS and JavaScript files, or any images you want to display. For example, create a CSS file:

mkdir public
touch public/styles.css

Edit styles.css with some basic styling:

/* public/styles.css */
body {
    background-color: lightblue;
    font-family: Arial, sans-serif;
}

h1 {
    color: navy;
    margin-left: 20px;
}

This CSS file will be served statically and linked in the HTML templates.


Step 5: Setting Up Views with EJS and Pug

Create a views directory with subdirectories for EJS and Pug templates:

mkdir -p views/ejs views/pug
EJS Template

In the views/ejs directory, create a file named index.ejs:

<!-- views/ejs/index.ejs -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Home</title>
    <link rel="stylesheet" href="/styles.css">
</head>
<body>
    <h1>Welcome to the Express.js app with EJS!</h1>
    <p>This page is rendered using <strong>EJS</strong> template engine.</p>
</body>
</html>
Pug Template

Similarly, in the views/pug directory, create a file named index.pug:

// views/pug/index.pug
doctype html
html(lang="en")
  head
    meta(charset="UTF-8")
    meta(name="viewport", content="width=device-width, initial-scale=1.0")
    title Home
    link(rel="stylesheet", href="/styles.css")
  body
    h1 Welcome to the Express.js app with Pug!
    p This page is rendered using #[strong Pug] template engine.

Step 6: Defining Routes

Next, we'll define routes in server.js to handle incoming requests and render the appropriate views.

For EJS:

// Serve the EJS homepage
app.get('/', (req, res) => {
    res.render('index'); // No extension needed as the view engine is set to EJS
});

For Pug:

Comment out the existing app.get() route for EJS and add a new route for Pug:

// Serve the Pug homepage
app.get('/', (req, res) => {
    res.render('index'); // Ensure that the views folder points to the correct engine
});

If you decide to use Pug, make sure to adjust the app.set() configurations for views to point to the views/pug directory instead of views/ejs.


Step 7: Running the Application

In your terminal, run the following command to start the server:

node server.js

Once the server is running, open your web browser and visit http://localhost:3000. Depending on your currently configured view engine (EJS or Pug), you should see a styled welcome message.


Understanding the Data Flow

  1. Request is Made: A client makes a request to http://localhost:3000.
  2. Server Receives Request: The Express server listens for requests on port 3000.
  3. Route Handling: The defined route handler (app.get('/')) is triggered.
  4. View Rendering:
    • If using EJS, the index.ejs file is located in views/ejs and rendered to HTML.
    • If using Pug, the index.pug file is located in views/pug and compiled to HTML.
  5. Response Sent: The server responds with the rendered HTML.
  6. Static Files Served: Any references to static files (like styles.css) are resolved and served from the public directory.

Conclusion

By following these steps, you have successfully created an Express.js application that serves static files and uses both EJS and Pug as templating engines. You learned how to set up routes, serve static assets, and manage view rendering according to different templating engines. This foundation allows for further enhancements and more complex applications.