Last updated on 7th March 2026

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>&copy; {{ 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

  1. Sign up at deployhq.com
  2. Connect your Git repository
  3. 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.