Global Data with app.locals
When you need data available in every template across your entire application, app.locals is the place to put it. This is perfect for site-wide settings, user info, or configuration values.
app.locals.siteName = 'My Awesome App';
app.locals.year = new Date().getFullYear();
These values are now accessible in any EJS file without passing them explicitly.
<footer>
<p>© <%= year %> <%= siteName %></p>
</footer>
Try it Yourself →
Request-Specific Data with res.locals
While app.locals persists across requests, res.locals is scoped to a single request. Use it for data that changes per request, like the current user or flash messages.
app.use((req, res, next) => {
res.locals.currentUser = req.user || null;
res.locals.success = req.flash('success');
res.locals.error = req.flash('error');
next();
});
Now every template in the request cycle has access to these values.
<% if (currentUser) { %>
<p>Welcome back, <%= currentUser.name %>!</p>
<% } %>
<% if (success.length) { %>
<div class="alert"><%= success %></div>
<% } %>
Try it Yourself →
Middleware that Adds Data to Templates
You can create custom middleware that injects data into every template. This keeps your routes clean and your data logic centralized.
app.use((req, res, next) => {
res.locals.navItems = [
{ name: 'Home', path: '/' },
{ name: 'About', path: '/about' },
{ name: 'Contact', path: '/contact' }
];
next();
});
Your navigation template can now use this data without any route-level configuration.
<nav>
<% navItems.forEach(item => { %>
<a href="<%= item.path %>"><%= item.name %></a>
<% }); %>
</nav>
Flash Messages Pattern
Flash messages provide temporary feedback to users after actions like form submissions or authentication. Combined with EJS, they create a smooth user experience.
const flash = require('express-flash');
app.use(flash());
app.post('/login', (req, res) => {
req.flash('success', 'Logged in successfully!');
res.redirect('/dashboard');
});
Display flash messages in your layout template so they appear on any page.
<% if (locals.success && success.length) { %>
<div class="flash success">
<%= success %>
</div>
<% } %>
<% if (locals.error && error.length) { %>
<div class="flash error">
<%= error %>
</div>
<% } %>
Try it Yourself →
Combining Multiple Middleware
You can stack multiple middleware functions to build up template data progressively. Each one adds or modifies data before the template renders.
app.use(setGlobalData);
app.use(setUserData);
app.use(setNavigationData);
app.get('/', (req, res) => {
res.render('home');
});
This layered approach keeps your code modular and easy to maintain. Each middleware handles one responsibility.
<div class="layout">
<%- include('partials/nav') %>
<main><%- body %></main>
<%- include('partials/footer') %>
</div>