Skip to main content
Node.js Basics
CHAPTER 17 Beginner

Express.js Templating Engines

Updated: May 13, 2026
25 min read

# Express.js Templating Engines

Welcome to Chapter 17! In the last chapter, we served static HTML files. The problem with static HTML is that it's exactly the same for every user.

If John logs in, he should see <h1>Welcome John</h1>. If Sarah logs in, she should see <h1>Welcome Sarah</h1>. You cannot achieve this with a static .html file. We need a way to combine HTML with backend JavaScript data *before* sending it to the user. To do this, we use a Templating Engine.

---

1. Introduction

A Templating Engine allows you to write HTML templates that contain special placeholder syntax.

When a user requests a page, Express takes the template, injects your backend data (like a username from the database) into the placeholders, and "renders" a final, standard HTML string that it sends to the browser.

There are many engines available (Pug, Handlebars, Nunjucks), but EJS (Embedded JavaScript) is the most popular for beginners because its syntax is almost exactly like standard HTML, just with some JavaScript tags thrown in.

---

2. Learning Objectives

By the end of this chapter, you will be able to:

  • Install and configure EJS in an Express application.
  • Create dynamic templates in the views directory.
  • Use res.render() to serve templates to the client.
  • Inject variables into an EJS template (<%= %>).
  • Write logic (loops and if statements) inside an EJS template (<% %>).
  • Pass complex arrays and objects to the frontend.

---

3. Beginner-Friendly Explanations

How EJS Works

EJS stands for Embedded JavaScript. It uses special tags:
  • <%= value %> : The equal sign = means "evaluate this JavaScript and print the result into the HTML." Use this for variables.
  • <% if(user) { %> : The lack of an equal sign means "run this JavaScript logic, but do not print anything." Use this for if statements and for loops.

The views Folder

Express has a convention: it looks for all your template files inside a folder named views. EJS files use the .ejs file extension instead of .html.

---

4. Syntax Explanation

Let's set up EJS and render our first template.

Server Setup (app.js): ```javascript id="ch17-syntax-1" const express = require('express'); const app = express();

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

app.get('/', (req, res) => { // 2. We use res.render() instead of res.send() // It looks for a file named "index.ejs" in the "views" folder. // The second argument is an object containing the dynamic data. res.render('index', { username: "Alice_99" }); });

app.listen(3000);

1
**Template (`views/index.ejs`):**

html id="ch17-syntax-2" <!-- Standard HTML --> <html> <body> <!-- The EJS tag will be replaced by the value of username --> <h1>Welcome back, <%= username %>!</h1> </body> </html>

1234567891011121314151617181920
**Output Explanation:**
When a user visits `/`, Express reads the `index.ejs` file, sees the `<%= username %>` tag, injects `"Alice_99"`, and sends the browser `<h1>Welcome back, Alice_99!</h1>`.

---

## 5. Real-world Examples

**Social Media Feeds:**
Imagine an Instagram clone. You don't create an HTML page for every single post.
You create one template: `feed.ejs`. 
The backend fetches an array of 50 posts from the database. It passes that array to `res.render('feed', { posts: postsArray })`.
Inside `feed.ejs`, you use an EJS `forEach` loop to dynamically generate 50 HTML `<div>` cards for the posts!

---

## 6. Multiple Code Examples

### Example 1: Installing EJS
Before using it, you must install it via NPM. You do *not* need to `require('ejs')` in your code; Express handles it behind the scenes once you `app.set('view engine', 'ejs')`.

bash id="ch17-bash-1" npm install ejs

1234
### Example 2: EJS Logic (If/Else Statements)
You can conditionally show HTML based on variables.

**`app.js`**:

javascript id="ch17-code-1" app.get('/dashboard', (req, res) => { res.render('dashboard', { isLoggedIn: true, name: "Bob" }); });

1
**`views/dashboard.ejs`**:

html id="ch17-code-2" <% if (isLoggedIn) { %> <h2>Hello <%= name %>, here is your private data!</h2> <% } else { %> <h2>Please log in to view this page.</h2> <% } %>

123456
*Notice how every line of JavaScript logic must be wrapped in `<% %>`, but the HTML in between is normal!*

### Example 3: EJS Loops (Rendering Lists)
This is incredibly common for displaying items from a database.

**`app.js`**:

javascript id="ch17-code-3" app.get('/store', (req, res) => { const products = [ { name: "Laptop", price: 999 }, { name: "Mouse", price: 25 }, { name: "Keyboard", price: 75 } ]; res.render('store', { items: products }); });

1
**`views/store.ejs`**:

html id="ch17-code-4" <h1>Our Products</h1> <ul> <% items.forEach(product => { %> <li> <strong><%= product.name %></strong> - $<%= product.price %> </li> <% }) %> </ul>

123456789101112131415161718192021222324252627282930313233343536
---

## 7. Output Explanations

In Example 3, the EJS loop iterates 3 times. Express generates 3 distinct `<li>` tags and populates them with the specific data for each item. By the time the HTML reaches the browser, all EJS tags are gone. The browser only sees clean, pure HTML. If a user "Inspects Element", they will never see `<% %>` tags.

---

## 8. Common Mistakes

1. **Forgetting to install EJS:** If you run the code without `npm install ejs`, Express will throw an error saying "Cannot find module 'ejs'".
2. **Wrong folder name:** Express explicitly looks for a folder named exactly `views`. If you name it `view`, `templates`, or `pages`, `res.render` will fail unless you manually configure the views path.
3. **Syntax Errors in Tags:** Forgetting the closing tag `%>` or mixing up `<%=` (for printing) with `<%` (for logic) will cause massive rendering errors.

---

## 9. Best Practices

- **Partial Templates:** If you have a Navbar and Footer that appear on every page, you shouldn't copy-paste them into every `.ejs` file. EJS supports "Partials" using `<%- include('partials/navbar') %>` to keep your code DRY (Don't Repeat Yourself). (The `-` means render raw HTML).
- **Combine Static and Dynamic:** You should still use `app.use(express.static('public'))` to serve CSS files. In your `.ejs` files, you simply link to the CSS file exactly as you did with static HTML.

---

## 10. Exercises

1. Install `ejs` in a project. Create a `views` folder.
2. Create an Express route `/weather`. Pass an object `{ city: "London", temp: 15, isRaining: true }`.
3. Create `views/weather.ejs`. Display the city and temp. Use an `if` statement to show "Bring an umbrella!" if `isRaining` is true.

---

## 11. Mini Project: Dynamic blog homepage

**Objective:** Build a blog homepage that dynamically renders a list of articles using EJS.

**Step 1:** Terminal Setup

bash npm init -y npm install express ejs mkdir views mkdir public

1
**Step 2:** Static CSS (`public/style.css`)

css body { font-family: Arial; padding: 20px; background: #f4f4f4; } .article-card { background: white; padding: 15px; margin-bottom: 10px; border-radius: 5px; box-shadow: 0 2px 5px rgba(0,0,0,0.1); } .author { color: gray; font-size: 0.9em; }

1
**Step 3:** The Server (`app.js`)

javascript id="ch17-mini-project-1" const express = require('express'); const app = express();

app.set('view engine', 'ejs'); app.use(express.static('public')); // Serve CSS

// Mock Database const blogPosts = [ { title: "Learning Node.js", author: "Jane Doe", date: "Oct 10", content: "Node is awesome!" }, { title: "Express Routing", author: "John Smith", date: "Oct 12", content: "Routing is easy." }, { title: "Why I love EJS", author: "Jane Doe", date: "Oct 15", content: "Dynamic HTML is great." } ];

app.get('/', (req, res) => { res.render('home', { posts: blogPosts, title: "My Tech Blog" }); });

app.listen(3000, () => console.log('Blog running on port 3000'));

1
**Step 4:** The Template (`views/home.ejs`)

html id="ch17-mini-project-2" <!DOCTYPE html> <html> <head> <title><%= title %></title> <link rel="stylesheet" href="/style.css"> </head> <body> <h1><%= title %></h1> <% if (posts.length === 0) { %> <p>No posts available at this time.</p> <% } else { %> <!-- Loop through posts --> <% posts.forEach(post => { %> <div class="article-card"> <h2><%= post.title %></h2> <p class="author">By <%= post.author %> on <%= post.date %></p> <p><%= post.content %></p> </div> <% }) %> <% } %> </body> </html> ``

Run it: node app.js -> Visit localhost:3000

---

12. Coding Challenges

Challenge 1: Modify the blog project. Add a new route /post/:id. When the user visits /post/0, it should pass *only* blogPosts[0] to a new template called singlePost.ejs to render a full-page view of just that one article.

Challenge 2: Explore EJS Partials. Create a folder views/partials. Create a file header.ejs containing the <!DOCTYPE html>... tags, and include it at the top of your home.ejs file.

---

13. MCQs with Answers

Q1: What is the primary purpose of a Templating Engine? A) To write CSS faster. B) To connect to a database securely. C) To inject dynamic server-side data into HTML pages before sending them to the client. D) To serve static files like images. Answer: C

Q2: Which method is used to send a template to the browser? A) res.sendTemplate() B) res.html() C) res.render() D) res.sendFile() Answer: C

Q3: Which EJS tag is used to OUTPUT a variable into the HTML? A) <% variable %> B) <%= variable %> C) {{ variable }} D) <%- variable %> Answer: B

Q4: By default, which directory does Express look in to find your EJS templates? A) /public B) /templates C) /pages D) /views Answer: D

---

14. Interview Questions

  1. 1. How does Server-Side Rendering (SSR) with engines like EJS differ from Client-Side Rendering (like React)?
*Answer:* With SSR (EJS), the server constructs the final HTML string, populated with data, and sends a complete page to the browser. It is excellent for SEO. With Client-Side Rendering, the server sends a blank HTML page and a massive JS file. The browser downloads the JS, requests raw data (JSON) via an API, and builds the HTML on the user's device.
  1. 2. What is the difference between <%= %> and <% %> in EJS?
*Answer:* <%= %> evaluates the JavaScript expression and outputs (prints) the result directly into the HTML document. <% %> executes JavaScript logic (like loops or conditionals) silently without outputting anything to the HTML.

---

15. FAQs

Q: Do I need to learn EJS if I already know React? A: Knowing how to build a JSON API (which React consumes) is more critical today. However, understanding templating engines is essential for rendering server-side emails, generating PDFs, and working on older full-stack codebases.

Q: Can I use CSS inside an EJS file? A: Yes! It works exactly like HTML. You can use <style> tags, or preferably, link to an external stylesheet hosted in your public folder.

---

16. Summary

  • Templating Engines blend static HTML with dynamic backend data.
  • EJS is a popular engine configured via app.set('view engine', 'ejs').
  • Templates must be stored in the views directory.
  • Use res.render('filename', { data }) to generate and send the page.
  • Use <%= %> for printing variables, and <% %>` for logical control flow.

---

17. Next Chapter Recommendation

Templating engines are great, but the modern web runs on APIs. Frontend frameworks (React, Vue) and mobile apps (iOS, Android) don't want HTML templates; they want raw data. In Chapter 18: REST API Development with Express, we will pivot back to building APIs that respond with structured JSON data.

Finish this Chapter

Save your progress on your learning path and prepare for coding interview challenges.

Discussion

Join the discussion

Log in or create a free account to participate.

Sort: ·