Labs ICT
Pro Login

Integration with Frontend

EJS with React/Vue, email templates, and PDF generation.

EJS Beyond Server-Side HTML

EJS isn't limited to rendering web pages on the server. You can use it anywhere you need to generate text from templates — emails, PDFs, CLI output, and even as a complement to frontend frameworks.

EJS + React or Vue

You can use EJS to generate the initial HTML shell that loads your React or Vue app. The template renders the static parts while the frontend framework takes over client-side.


// views/index.ejs



  <%= title %>
  


  
<%- include('noscript') %>

This pattern gives you server-rendered initial content for SEO and fast loading, while the JavaScript framework hydrates the page for interactivity.

Email Templates with EJS

Email HTML needs to be self-contained. EJS is perfect for generating email bodies with personalized content.


const nodemailer = require('nodemailer')
const ejs = require('ejs')
const path = require('path')

async function sendWelcomeEmail(user) {
  const html = await ejs.renderFile(
    path.join(__dirname, 'views/emails/welcome.ejs'),
    { name: user.name, loginUrl: 'https://myapp.com/login' }
  )

  await transporter.sendMail({
    to: user.email,
    subject: 'Welcome to Our App!',
    html: html
  })
}
    

Your email template stays clean and readable.


// views/emails/welcome.ejs



  

Welcome, <%= name %>!

Thanks for joining. We're excited to have you.

Log In to Your Account

If you didn't create this account, ignore this email.

Inline styles are necessary for email clients. EJS lets you keep the structure clean while embedding dynamic values.

Try it Yourself →

EJS for PDF Generation

Libraries like Puppeteer or pdf-lib can convert HTML to PDF. Render your HTML with EJS first, then pass it to the PDF generator.


const puppeteer = require('puppeteer')
const ejs = require('ejs')

async function generateInvoice(order) {
  const html = await ejs.renderFile('./views/invoice.ejs', {
    orderId: order.id,
    items: order.items,
    total: order.total,
    date: new Date().toLocaleDateString()
  })

  const browser = await puppeteer.launch()
  const page = await browser.newPage()
  await page.setContent(html, { waitUntil: 'networkidle0' })
  const pdf = await page.pdf({ format: 'A4', printBackground: true })
  await browser.close()
  return pdf
}
    

Your invoice template is regular HTML with EJS variables. The PDF output looks exactly like what you designed in the template.

EJS for CLI Output

Command-line tools can use EJS to format output. Render templates to produce colorful, structured terminal output.


const ejs = require('ejs')
const chalk = require('chalk')

const template = `
<%= chalk.green('✓') %> <%= title %>
<%= message %>

<% items.forEach(item => { %>
   <%= item %>
<% }) %>
`

const output = ejs.render(template, {
  chalk,
  title: 'Build Complete',
  message: 'All files compiled successfully',
  items: ['app.js (2.3kb)', 'styles.css (1.1kb)', 'index.html (0.8kb)']
})

console.log(output)
    

This keeps your CLI output formatting in a template rather than scattered across console.log calls with string concatenation.

EJS as a Configuration Renderer

Generate configuration files from templates. Useful when config values depend on environment variables or computed values.


const ejs = require('ejs')
const fs = require('fs')

const configTemplate = `
module.exports = {
  db: {
    host: '<%= process.env.DB_HOST %>',
    port: <%= process.env.DB_PORT || 5432 %>,
    name: '<%= process.env.DB_NAME %>'
  },
  redis: {
    url: '<%= process.env.REDIS_URL %>'
  },
  features: {
    darkMode: <%= features.darkMode %>,
    betaFeatures: <%= features.beta %>
  }
}
`

const config = ejs.render(configTemplate, {
  features: { darkMode: true, beta: false }
})

fs.writeFileSync('config.js', config)
    

This approach keeps your configuration readable while allowing dynamic values and conditionals.

Streaming EJS Output

For large templates, EJS can stream output instead of buffering the entire result. This improves time-to-first-byte for big pages.


const ejs = require('ejs')
const fs = require('fs')

app.get('/report', (req, res) => {
  const templatePath = './views/report.ejs'
  const stream = ejs.renderFile(templatePath, {
    rows: largeDataSet
  }, (err, str) => {
    if (err) return res.status(500).send('Error')
    res.send(str)
  })
})
    

For truly large outputs, look into ejs.escapeStream or pipe-based approaches that send chunks as they're rendered.