Stop 05 · Express.js & Web FrameworksTopics · 11/14

Templating (EJS/Pug)

Part of the Backend Developer Roadmap

In short

Not every backend returns JSON. Admin panels, emails and simple sites often send ready-made HTML. Template engines fill your data into HTML on the server.

Server-side templating engines that let Express render dynamic HTML pages directly from the backend — less common now with API + frontend-framework architectures, but still used for emails and simple server-rendered apps.

The mascot fills a blank line on one of a stack of identical invitation cards.

Think of it like this

Wedding invitation cards

The printer makes 500 identical cards with one blank line: 'Dear ______'. The family fills in each guest's name. A template is that printed card, and res.render fills in the blanks with your data for each request.

Watch it happen

From data to HTML

Route
Load data
Template
HTML
Browser

1/5GET /orders/A102 hits a route that will render a page instead of JSON.

The big ideas

What you need to know

Server-side rendering

The server builds the full HTML page. Good for emails, admin panels and simple, fast sites.

EJS looks like HTML

EJS is HTML with <%= value %> for output and <% %> for loops and ifs. Easy if you know HTML.

Pug uses indentation

Pug drops angle brackets and closing tags. Shorter, but you need to learn its syntax.

Escape by default

<%= %> escapes HTML so a user's name can't inject a script. <%- %> doesn't escape; use it rarely.

See it in code

Walk through the code

js
1// index.js2app.set("view engine", "ejs");   // looks in ./views by default3 4app.get("/orders/:id", async (req, res) => {5  const order = await db.orders.findById(req.params.id);6  res.render("order", { order });7});8 9// views/order.ejs10// <h1>Order <%= order.id %></h1>11// <ul>12//   <% order.items.forEach((item) => { %>13//     <li><%= item.name %> x <%= item.qty %></li>14//   <% }) %>15// </ul>

1/4Tell Express to use EJS. Templates live in a views folder by default.

Install with npm i ejs. You don't need to import it; Express loads it when you set the view engine.

Save yourself the pain

Common mistakes

Oops

Using <%- user.bio %> to print text users typed.

Do this instead

Use <%= %> for anything from users. Unescaped output lets someone inject a script into your page.

Oops

Putting database queries inside the template.

Do this instead

Load all data in the route, then pass it to render. Templates should only display.

Your mission

Render an order page

~25 min

Quick check

In EJS, what's the difference between <%= name %> and <%- name %>?

Go deeper

  1. 1Render a dynamic page with EJS, passing data from a route handler.
  2. 2Build an HTML email template using a templating engine.
  3. 3Understand why most modern apps separate the API from HTML rendering with a frontend framework instead.

More topics at this stop

Stuck on this topic? Ask an Insider

Get 1:1 guidance from people who've walked this exact path — on the InsideEdge app.

Download
InsideEdge