> **New in 2026 — managed Static Hosting**: DeployHQ now offers [Static Hosting](https://www.deployhq.com/hosting/static) — fully-managed deployment to Cloudflare's edge, no server to provision. Eleventy's `_site/` build output drops straight into the Static Hosting subdirectory setting. The walkthrough below covers BYO-server deployment, which remains fully supported.

**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:

```bash
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`):

```javascript
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`):**

```html
<!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`):**

```markdown
---
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:

```markdown
---
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:

```yaml
---
pagination:
  data: collections.posts
  size: 10
  alias: posts
permalink: "blog/page-{{ pagination.pageNumber + 1 }}/"
---
```

### Image Optimization

Use the official `@11ty/eleventy-img` plugin:

```bash
npm install @11ty/eleventy-img
```

```javascript
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

```bash
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](https://www.deployhq.com/signup)
2. Connect your Git repository
3. Webhook installs automatically

### Configure Build Command

```bash
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

```nginx
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:

```bash
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:

```markdown
{% 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](https://www.deployhq.com/guides).

[Sign up for DeployHQ](https://www.deployhq.com/signup) — free for one project.

Questions? Contact [support@deployhq.com](mailto:support@deployhq.com) or find us on [Twitter/X](https://x.com/deployhq).
