SSI vs CSI: Understanding Server-Side and Client-Side Includes


In web development, content reuse is a common challenge. Whether itβs a header, footer, navigation menu, or any repeated block of HTML, you donβt want to copy and paste the same code into every file. Instead, you'd want a system that can include shared content automatically.
This is where SSI (Server-Side Includes) and CSI (Client-Side Includes) come into play. Both are techniques for injecting reusable content, but they operate at different points in the rendering pipeline.
What is SSI (Server-Side Includes)?
Server-Side Includes (SSI) is a feature of web servers (like Apache or Nginx) that allows you to include the content of one file inside another on the server, before the page is sent to the user's browser.
How SSI Works
The server reads your HTML page.
When it finds an SSI directive (e.g.,
<!--#include file="header.html" -->
), it replaces that tag with the contents of the specified file.Then it sends the final page to the client.
Example (Apache):
<!--#include virtual="/includes/header.html" -->
This would include header.html
from the /includes/
folder into the current page.
Configuration (Apache):
To use SSI with Apache:
Options +Includes
AddType text/html .shtml
AddOutputFilter INCLUDES .shtml
What is CSI (Client-Side Includes)?
Client-Side Includes (CSI) are similar in purpose β injecting reusable content β but the inclusion happens in the browser, after the page is loaded. Typically done with JavaScript (often using fetch()
or XMLHttpRequest
), CSI lets the client pull in content dynamically.
Example:
<div id="header"></div>
<script>
fetch('/includes/header.html')
.then(res => res.text())
.then(html => {
document.getElementById('header').innerHTML = html;
});
</script>
Implementing SSI in Node.js (Express)
If you're building a server with Node.js and Express, and want to simulate SSI without importing external libraries or using a template engine, you can do this manually with basic file operations.
File Structure
project/
βββ views/
β βββ header.html
β βββ footer.html
β βββ index.html β contains only main content
βββ server.js
views/index.html
<h1>Welcome to My Website</h1>
<p>This is the main content of the homepage.</p>
server.js
const express = require('express');
const fs = require('fs');
const path = require('path');
const app = express();
const PORT = 3000;
function renderWithIncludes(filePath) {
const rawHtml = fs.readFileSync(filePath, 'utf8');
return rawHtml.replace(/<!--#include\s+file="(.+?)"\s*-->/g, (_, includePath) => {
const fullIncludePath = path.join(path.dirname(filePath), includePath);
if (fs.existsSync(fullIncludePath)) {
return fs.readFileSync(fullIncludePath, 'utf8');
}
return `<!-- Missing include: ${includePath} -->`;
});
}
app.get('/', (req, res) => {
const mainPath = path.join(__dirname, 'views', 'index.html');
const fullHtml = `
<!DOCTYPE html>
<html>
<head><title>Home</title></head>
<body>
<!--#include file="header.html" -->
${fs.readFileSync(mainPath, 'utf8')}
<!--#include file="footer.html" -->
</body>
</html>
`;
const finalHtml = renderWithIncludes(path.join(__dirname, 'views', 'temp.html'));
res.send(finalHtml);
});
app.listen(PORT, () => {
console.log(`Server is running at http://localhost:${PORT}`);
});
In this example, you can manually or programmatically build a
temp.html
page containing<!--#include file=... -->
tags and then process it withrenderWithIncludes()
.
Why Prefer SSI (Without Libraries or Web Components)?
There are several valid reasons why you might prefer using a custom SSI-like setup instead of bringing in a full templating engine (like EJS or Handlebars) or modern web components:
1. Simplicity
If your site is mostly static, and you just want to reuse headers and footers, you donβt need a heavy framework or build step.
A basic SSI-like file reader avoids complexity and dependencies.
2. Zero Dependencies
Pure Node.js + Express +
fs
module is often enough for simple websites.Reduces install size, build steps, and attack surface (especially for internal tools or small projects).
3. Performance
- With SSI, the server builds full HTML before sending it to the browser, leading to faster initial page loads and SEO-friendly output.
4. No JavaScript on Client
CSI requires JavaScript to run in the browser β which can fail for users with JS disabled or impact SEO.
SSI ensures everything is pre-rendered.
5. Avoiding Web Components
Not all browsers support Web Components fully without polyfills.
They often require JavaScript + build tooling (e.g., Lit, Stencil), which you might want to avoid for simple projects.
SSI vs CSI
Feature | SSI (Server-Side) | CSI (Client-Side) |
Execution Point | On the server | In the browser |
Dependencies | None (can use built-in Node.js) | Requires JavaScript |
SEO Support | Fully crawlable (rendered server-side) | May be ignored by bots without JS |
Performance | Faster first load, content pre-rendered | May appear slower due to extra HTTP calls |
Flexibility | Limited to static file injection | Can use logic, conditions, APIs, etc. |
Use Case | Static content reuse | Dynamic content, personalization |
When to Use SSI
Use Server-Side Includes when:
Youβre working on a static or semi-static site
You want pre-rendered HTML for SEO
You donβt want to add libraries or frameworks
You want to reuse common layout fragments easily
When to Use CSI
Use Client-Side Includes when:
Your app is heavily dynamic or personalized
You already use client-side frameworks (React, Vue, etc.)
You're okay with extra HTTP calls and delayed rendering
SEO is not a concern (e.g., admin dashboards, internal apps)
Conclusion
Both SSI and CSI solve the same problem: HTML reuse. The best choice depends on your goals.
SSI is simple, fast, and SEO-friendly β perfect for lightweight or static sites.
CSI offers flexibility and dynamic capabilities but relies on JavaScript and client-side rendering.
For modern projects, you might use:
EJS, Handlebars, or Pug for server-side rendering
React or Vue for client-side rendering
Custom SSI (as shown above) when you want a no-dependency, no-framework approach
π Enjoyed this blog?
Reach out in the comments below or on LinkedIn to let me know what you think of it.
For more updates, do follow me here :)
Subscribe to my newsletter
Read articles from Aakanksha Bhende directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Aakanksha Bhende
Aakanksha Bhende
Software Engineer | Open Source Enthusiast | Mentor | Learner I love documenting stuff that I come across and find interesting. Hoping that you will love reading it and get to know something new :)