{"id":10781,"library":"ejs","title":"EJS Templating Engine","description":"EJS (Embedded JavaScript) is a popular, fast, and lightweight templating engine for Node.js and browsers. It enables the rendering of dynamic HTML by embedding plain JavaScript directly within template files using special tags like `<% %>` for control flow, `<%= %>` for escaped output, and `<%- %>` for unescaped raw output. The current stable version is 5.0.2, with an active release cadence. Key differentiators include its straightforward approach, leveraging native JavaScript for logic, and broad compatibility across Node.js environments (CommonJS and ES Modules) and all modern browsers, down to very old ones. It offers features such as static caching of compiled functions and templates, custom delimiters, and full compliance with the Express view system, making it a common choice for server-side rendering in web applications due to its simplicity and effectiveness.","status":"active","version":"5.0.2","language":"javascript","source_language":"en","source_url":"git://github.com/mde/ejs","tags":["javascript","template","templating","engine","ejs"],"install":[{"cmd":"npm install ejs","lang":"bash","label":"npm"},{"cmd":"yarn add ejs","lang":"bash","label":"yarn"},{"cmd":"pnpm add ejs","lang":"bash","label":"pnpm"}],"dependencies":[],"imports":[{"note":"EJS supports both ES Modules (import) and CommonJS (require). Use the appropriate syntax for your project's module system. ESM is generally preferred in modern Node.js applications.","wrong":"const ejs = require('ejs');","symbol":"ejs","correct":"import ejs from 'ejs';"},{"note":"The primary rendering functions like `render` and `compile` are properties of the default `ejs` import, not named exports. Access them directly from the imported `ejs` object.","wrong":"import { render } from 'ejs';\nconst html = render(templateString, data, options);","symbol":"ejs.render","correct":"import ejs from 'ejs';\nconst html = ejs.render(templateString, data, options);"},{"note":"`renderFile` is used for rendering templates from a file path. Like `render`, it is a method on the default `ejs` import, not a named export. It typically takes a callback function.","wrong":"import { renderFile } from 'ejs';","symbol":"ejs.renderFile","correct":"import ejs from 'ejs';\nejas.renderFile(filename, data, options, callback);"}],"quickstart":{"code":"import ejs from 'ejs';\nimport express from 'express';\nimport path from 'path';\n\nconst app = express();\nconst port = process.env.PORT ?? 3000;\n\n// Configure EJS as the view engine for Express\napp.set('view engine', 'ejs');\napp.set('views', path.join(__dirname, 'views'));\n\n// Create a simple EJS template file (e.g., views/index.ejs):\n// <!-- views/index.ejs -->\n// <!DOCTYPE html>\n// <html lang=\"en\">\n// <head>\n//     <meta charset=\"UTF-8\">\n//     <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n//     <title>EJS Example</title>\n// </head>\n// <body>\n//     <h1>Hello, <%= user.name %>!</h1>\n//     <% if (isAdmin) { %>\n//         <p>You are an administrator.</p>\n//     <% } else { %>\n//         <p>Welcome, regular user.</p>\n//     <% } %>\n//     <p>Current time: <%= currentTime.toLocaleTimeString() %></p>\n// </body>\n// </html>\n\n// Route to render a template file\napp.get('/', (req, res) => {\n  const userData = {\n    user: { name: 'Alice' },\n    isAdmin: true,\n    currentTime: new Date()\n  };\n  res.render('index', userData);\n});\n\n// Route to render a template string directly\napp.get('/direct', (req, res) => {\n  const templateString = `<h2>Direct Render</h2><p>Server says: <%= message %></p>`;\n  const data = { message: 'Hello from direct EJS render!' };\n  const html = ejs.render(templateString, data);\n  res.send(html);\n});\n\napp.listen(port, () => {\n  console.log(`EJS example app listening at http://localhost:${port}`);\n  console.log(`Try http://localhost:${port}/ and http://localhost:${port}/direct`);\n});\n","lang":"typescript","description":"This quickstart demonstrates setting up EJS with an Express application to render templates from files and also shows how to render EJS template strings directly using `ejs.render`."},"warnings":[{"fix":"Always use the explicit form `ejs.render(templateString, dataObject, optionsObject)` to clearly separate your template data from EJS rendering options.","message":"The shortcut `ejs.render(dataAndOptions)` where all template data and rendering options are passed in a single object is officially deprecated and not recommended. It was effectively removed as a reliable pattern starting from v3.0.0 due to potential conflicts if an internal option name clashes with a data property name, leading to unpredictable behavior.","severity":"breaking","affected_versions":">=3.0.0"},{"fix":"Migrate away from `ejs.filters`. Implement custom logic as helper functions passed directly within your template data, or preprocess your data before rendering to apply transformations.","message":"The `ejs.filters` object, which provided a global mechanism for defining custom filter functions, was removed in EJS v4.0.0. Any code relying on `ejs.filters` will no longer function.","severity":"breaking","affected_versions":">=4.0.0"},{"fix":"If dynamic cache clearing is a critical requirement, you may need to reconsider your application's caching strategy, potentially by managing template compilation and caching manually or at a higher application level.","message":"The `ejs.clearCache()` method, which allowed programmatic clearing of EJS's internal template cache, was removed in EJS v5.0.0. There is no direct public API to clear the cache anymore.","severity":"breaking","affected_versions":">=5.0.0"},{"fix":"NEVER pass unsanitized user input directly to EJS template rendering functions or configuration options. Always rigorously validate and sanitize all external input. Treat any user-supplied template content as hostile and potentially malicious.","message":"EJS templates are essentially JavaScript runtimes. Directly passing unchecked user input (e.g., from `req.query`, `req.body`, or `req.params`) as the template string or influencing sensitive options like `filename`, `root`, or `closeDelimiter` can lead to severe Server-Side Template Injection (SSTI) and Remote Code Execution (RCE) vulnerabilities. The EJS project explicitly warns against this, stating that the `render` function is not intended for untrusted input.","severity":"gotcha","affected_versions":">=0.12.18"},{"fix":"When using `strict: true` or `_with: false`, ensure all variables in your template are prefixed with `locals.` (e.g., `<%= locals.variableName %>`). Alternatively, explicitly set `_with: true` and `strict: false` if direct variable access is preferred and you understand the implications.","message":"By default, EJS uses JavaScript's `with()` statement (`_with: true`) to expose local variables directly in the template scope. However, when `strict: true` is enabled or `_with: false` is explicitly set, `with()` is not used. In these scenarios, template variables must be accessed via a `locals` object (e.g., `<%= locals.user.name %>` instead of `<%= user.name %>`), otherwise, a `ReferenceError` will occur.","severity":"gotcha","affected_versions":">=3.0.0"}],"env_vars":null,"last_verified":"2026-04-19T00:00:00.000Z","next_check":"2026-07-18T00:00:00.000Z","problems":[{"fix":"In your template, change `<%= variable_name %>` to `<%= locals.variable_name %>`. Alternatively, ensure `strict: false` and `_with: true` are set in your EJS rendering options if direct variable access is desired.","cause":"This typically occurs when EJS is running in strict mode (`strict: true`) or with `_with: false`, and template variables are accessed directly instead of through the `locals` object.","error":"ReferenceError: <variable_name> is not defined"},{"fix":"When using `ejs.compile` or `ejs.render` with includes, provide the `filename` option with the absolute path of the current template. For Express, configure `app.set('views', path.join(__dirname, 'views'))` and ensure include paths are correct relative to these view directories.","cause":"EJS cannot resolve the path for an included template. This usually happens when the `filename` option is missing (needed for relative paths), or the `root` or `views` options are not correctly configured to specify template directories.","error":"EJS: Could not find the include file \"partial.ejs\""},{"fix":"Remove any code referencing `ejs.filters`. Instead, pass custom helper functions as part of your template data object, or preprocess your data before passing it to EJS.","cause":"You are attempting to use the `ejs.filters` global object, which was deprecated and completely removed in EJS v4.0.0.","error":"TypeError: ejs.filters is not a function"},{"fix":"Always provide the `filename` option with the absolute path to your template file when `cache: true` is enabled. For example, `ejs.render(str, data, { cache: true, filename: '/path/to/template.ejs' })`.","cause":"You are attempting to use the `cache: true` option with `ejs.compile` or `ejs.render` without providing the `filename` option. EJS uses the `filename` as the key for its internal cache.","error":"Error: options.filename is required for caching"}],"ecosystem":"npm"}