Deploy Eleventy (11ty) Sites with DeployHQ
Prerequisites:
- Node.js 18 or later (Node.js 20 LTS recommended)
- A server with SSH or SFTP access
- A DeployHQ account
What is Eleventy?
Eleventy (11ty) is a simpler, more flexible static site generator built on Node.js. Unlike frameworks that ship heavy JavaScript bundles to the browser, Eleventy generates pure HTML by default — zero client-side JavaScript unless you explicitly add it.
Eleventy supports multiple templating languages (Nunjucks, Liquid, Markdown, JavaScript, WebC) and makes minimal assumptions about your project structure. It's the "bring your own everything" SSG — no mandatory directory conventions, no required config file, no framework lock-in.
Eleventy is particularly popular for blogs, documentation sites, and content-heavy websites where performance and simplicity matter.
Step 1: Install Eleventy
Create a new project:
mkdir my-site && cd my-site
npm init -y
npm install @11ty/eleventy
Or add to an existing project:
bash
npm install @11ty/eleventy
Verify:
bash
npx @11ty/eleventy --version
Step 2: Project Structure
Eleventy is flexible about structure. A typical project:
my-site/
├── src/ # Input directory
│ ├── _includes/ # Layouts and partials
│ │ ├── base.njk # Base layout
│ │ └── post.njk # Post layout
│ ├── _data/ # Global data files
│ │ └── site.json # Site metadata
│ ├── posts/ # Blog posts (Markdown)
│ │ ├── posts.json # Directory data (applies to all posts)
│ │ ├── first-post.md
│ │ └── second-post.md
│ ├── css/ # Styles (passed through)
│ │ └── style.css
│ ├── index.njk # Home page
│ └── about.md # About page
├── _site/ # Output directory (generated)
├── eleventy.config.js # Configuration
├── package.json
└── package-lock.json
Key Directories
- src/ — Input directory containing templates, content, and assets
- _includes/ — Layouts and reusable template partials. Referenced by name in front matter.
- _data/ — Global data files (JSON, JS, YAML). Available in all templates as
site.propertyName. - _site/ — Generated output. This is what gets deployed.
Step 3: Configuration
Create eleventy.config.js (or .eleventy.js):
module.exports = function(eleventyConfig) {
// Pass through static files
eleventyConfig.addPassthroughCopy("src/css");
eleventyConfig.addPassthroughCopy("src/images");
eleventyConfig.addPassthroughCopy("src/fonts");
// Custom collections
eleventyConfig.addCollection("posts", function(collectionApi) {
return collectionApi.getFilteredByGlob("src/posts/**/*.md")
.sort((a, b) => b.date - a.date);
});
// Custom filters
eleventyConfig.addFilter("dateFormat", function(date) {
return new Date(date).toLocaleDateString("en-GB", {
year: "numeric", month: "long", day: "numeric"
});
});
return {
dir: {
input: "src",
output: "_site",
includes: "_includes",
data: "_data"
},
templateFormats: ["md", "njk", "html"],
markdownTemplateEngine: "njk",
htmlTemplateEngine: "njk"
};
};
Step 4: Templating
Eleventy supports multiple template engines. Nunjucks is the most popular:
Base layout (src/_includes/base.njk):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{{ title }} | {{ site.name }}</title>
<meta name="description" content="{{ description or site.description }}">
<link rel="stylesheet" href="/css/style.css">
</head>
<body>
<header>
<nav>
<a href="/">Home</a>
<a href="/about/">About</a>
<a href="/posts/">Blog</a>
</nav>
</header>
<main>
{{ content | safe }}
</main>
<footer>
<p>© {{ site.name }} {{ page.date.getFullYear() }}</p>
</footer>
</body>
</html>
Blog post (src/posts/first-post.md):
---
title: My First Post
date: 2026-03-07
layout: post.njk
tags: posts
description: A description for SEO
---
This is my first blog post built with Eleventy.
Step 5: Core Features
Data Cascade
Eleventy merges data from multiple sources (highest priority first):
1. Front matter in the template
2. Template-specific data files (post.11tydata.js)
3. Directory data files (posts.json)
4. Global data files (_data/site.json)
5. Computed data
Collections
Group content using tags or custom collection logic:
---
tags: posts
---
Access in templates:
html
{% for post in collections.posts %}
<article>
<h2><a href="{{ post.url }}">{{ post.data.title }}</a></h2>
<time>{{ post.date | dateFormat }}</time>
</article>
{% endfor %}
Pagination
Generate pages from data:
---
pagination:
data: collections.posts
size: 10
alias: posts
permalink: "blog/page-{{ pagination.pageNumber + 1 }}/"
---
Image Optimization
Use the official @11ty/eleventy-img plugin:
npm install @11ty/eleventy-img
const Image = require("@11ty/eleventy-img");
module.exports = function(eleventyConfig) {
eleventyConfig.addShortcode("image", async function(src, alt, sizes) {
let metadata = await Image(src, {
widths: [300, 600, 1200],
formats: ["avif", "webp", "jpeg"],
outputDir: "./_site/img/",
urlPath: "/img/"
});
return Image.generateHTML(metadata, { alt, sizes, loading: "lazy" });
});
};
Use in templates:
markdown
{% image "src/images/hero.jpg", "Hero image", "(min-width: 600px) 600px, 100vw" %}
Plugins
Popular Eleventy plugins:
- @11ty/eleventy-plugin-rss — RSS feed generation
- @11ty/eleventy-plugin-syntaxhighlight — Code syntax highlighting
- @11ty/eleventy-navigation — Hierarchical navigation
- @11ty/eleventy-plugin-bundle — CSS and JS bundling
Step 6: Build for Production
npx @11ty/eleventy
Output goes to _site/:
_site/
├── index.html
├── about/
│ └── index.html
├── posts/
│ ├── index.html
│ ├── first-post/
│ │ └── index.html
│ └── second-post/
│ └── index.html
├── css/
│ └── style.css
├── img/
├── feed.xml
└── sitemap.xml
Step 7: Deploy with DeployHQ
Create a DeployHQ Project
- Sign up at deployhq.com
- Connect your Git repository
- Webhook installs automatically
Configure Build Command
cd %path% && npm ci && npx @11ty/eleventy
If you have a custom build script in package.json:
bash
cd %path% && npm ci && npm run build
Set Deployment Subdirectory
_site
This deploys only the generated output — not your source templates, node_modules, or data files.
Server Configuration
- Protocol: SSH or SFTP
- Deployment Path:
/var/www/eleventy-site/ - No post-deployment commands needed — pure static files
Nginx Configuration
server {
listen 443 ssl http2;
server_name example.com;
root /var/www/eleventy-site;
index index.html;
location ~* \.(css|js|png|jpg|jpeg|gif|svg|ico|woff|woff2|avif|webp)$ {
expires 30d;
add_header Cache-Control "public, immutable";
}
location / {
try_files $uri $uri/ $uri/index.html =404;
expires 1h;
}
error_page 404 /404.html;
}
Environment Variables
If your Eleventy site fetches data at build time (from a CMS API, for example), configure environment variables in DeployHQ's Configuration Files:
CMS_API_URL=https://cms.example.com/api
CMS_API_KEY=your-api-key
Access in _data/ files:
javascript
// src/_data/posts.js
module.exports = async function() {
const response = await fetch(process.env.CMS_API_URL + "/posts", {
headers: { Authorization: `Bearer ${process.env.CMS_API_KEY}` }
});
return response.json();
};
Step 8: Troubleshooting
Output Directory is Empty
Check your eleventy.config.js input/output paths. If the input directory doesn't match where your files are, nothing gets built.
Template Engine Errors
Eleventy processes .md files through Nunjucks by default. If your markdown contains {{ }} or {% %} syntax (common in code examples), escape them:
{% raw %}
{{ variable }}
{% endraw %}
Slow Builds with Image Processing
@11ty/eleventy-img processes images at build time. For large image sets, this can be slow. Solutions:
- Use the .cache directory (enabled by default) — images are only processed once
- Ensure .cache/ is in your .gitignore but consider sharing it across builds
Data File Not Loading
Data files in _data/ must export the data. For JavaScript files:
```javascript
// Correct
module.exports = { name: "My Site" };
// Also correct (async) module.exports = async function() { return { name: "My Site" }; }; ```
Conclusion
Eleventy's simplicity is its superpower — zero client-side JavaScript, flexible templating, and a minimal learning curve. Paired with DeployHQ, your content goes from Git push to live site in seconds, with only the changed files transferred.
Browse more deployment guides in the DeployHQ guides library.
Sign up for DeployHQ — free for one project.
Questions? Contact support@deployhq.com or find us on Twitter/X.