EJS Template Engine Guide for Backend Engineers
EJS (Embedded JavaScript Templates) is a simple yet powerful templating language that lets you generate HTML markup with plain JavaScript. The “E” can stand for “Embedded,” “Effective,” “Elegant,” or simply “Easy” - all of which describe this lightweight templating engine.
EJS follows a simple philosophy: use JavaScript for template logic without inventing a new syntax.
As a backend engineer, you’ll appreciate EJS for its simplicity and flexibility. Unlike other templating engines that require learning a new syntax, EJS uses plain JavaScript, making it immediately accessible to anyone familiar with JS.
1 | // Simple EJS example |
EJS is particularly useful when:
- You need to dynamically generate HTML from data on the server
- You want to avoid reinventing control flow structures
- You prefer to work directly with JavaScript rather than learn a new templating language
- You want a straightforward way to include partials and layouts for code reuse
EJS Tags
EJS provides a variety of tags for different templating needs:
1. <% %>
(Scriptlet Tag)
Used for control flows and JavaScript logic without outputting anything.
1 | <% if (user) { %> |
2. <%= %>
(Output Tag - HTML Escaped)
Outputs the value into the template, escaping any HTML characters to prevent XSS attacks.
1 | <p>User input: <%= userComment %></p> |
3. <%- %>
(Output Tag - Unescaped)
Outputs the unescaped value. Useful for including HTML content or partials.
1 | <%- include('partials/header') %> |
4. <%# %>
(Comment Tag)
Used for comments that won’t be included in the output.
1 | <%# This comment won't appear in the rendered HTML %> |
5. Additional Tags
<%_
and_%>
: “Whitespace Slurping” tags that remove whitespace<%%
: Outputs a literal ‘<%’-%>
and_%>
: Trim-mode tags that control whitespace
Security Tip: Always use
<%= %>
(escaped output) when rendering user-provided data to prevent XSS attacks.
Passing Data to EJS Templates
Server to EJS
A key part of using EJS is passing data from your server to your templates. This is typically done with an object passed as the second parameter to the render
function.
1 | // In Express.js |
Then in your EJS template:
1 | <h1><%= title %></h1> |
Handling Missing Data Safely
When working with data that might not be available, it’s good practice to check for its existence to avoid errors. There are several approaches:
- Using conditional checks:
1 | <% if (locals.user) { %> |
- Using the
locals
object:
1 | <h2>Welcome, <%= locals.user ? user.name : 'Guest' %></h2> |
The locals
object contains all variables passed to the template, so locals.user
will be undefined
if no user was passed rather than throwing an error.
- Using optional chaining (ES2020):
1 | <h2>Welcome, <%= user?.name || 'Guest' %></h2> |
Best Practice: The
locals
approach is preferred for robust templates as it prevents “variable is not defined” errors that might crash your application.
EJS to Server (Form Submission)
Data can flow back to the server through HTML forms:
1 | <form action="/submit" method="post"> |
On the server with Express:
1 | // Don't forget to include body-parser middleware |
EJS Partials and Layouts
Partials and layouts allow you to organize and reuse code across multiple pages, which is crucial for maintaining consistent design and reducing duplication.
Partials
Partials are reusable template fragments that can be included in other templates:
1 | <!-- views/partials/header.ejs --> |
1 | <!-- views/partials/footer.ejs --> |
Then include them in your main template:
1 | <!-- views/index.ejs --> |
Note: When including partials, use the
<%-
tag to ensure the HTML isn’t escaped.
Layouts
While EJS doesn’t have built-in layout support like some template engines, you can implement layouts using partials:
1 | <!-- views/layouts/main.ejs --> |
To use this layout, you can create a wrapper function:
1 | // In your Express app setup |
Alternatively, you can use the express-ejs-layouts
package for more streamlined layout support.
Using EJS to Generate a Static Website
EJS isn’t just useful for dynamic web applications; it can also be used to generate static websites. Here’s how:
Basic Static Site Generation
- Create a project structure:
1 | /static-site-generator |
- Define your data:
1 | // data/site.json |
- Create your templates:
1 | <!-- templates/layout.ejs --> |
- Create the generator script:
1 | // generator.js |
- Run the generator:
1 | node generator.js |
Advanced Features for Static Site Generation
For a more robust static site generator with EJS, you might want to:
- Add support for Markdown content using a package like
marked
- Implement a blog with automatic post listing and pagination
- Create an asset pipeline for preprocessing CSS and JavaScript
- Add a dev server for local development with live reloading
- Implement a build process for optimizing images and other assets
Here’s an example of converting Markdown to HTML with EJS:
1 | const ejs = require('ejs'); |
Conclusion
EJS is a flexible, approachable templating engine that brings the familiarity of JavaScript to server-side HTML generation. For backend engineers, it provides a straightforward way to create dynamic content without the overhead of learning a complex templating language.
Whether you’re building a traditional server-rendered application, creating reusable components through partials, or generating a static site, EJS offers a set of simple but powerful tools to get the job done efficiently.
By leveraging JavaScript’s expressiveness within HTML templates, EJS strikes a balance between flexibility and simplicity that makes it a solid choice for many projects.