Build a blog with Eleventy

Write posts in Markdown, run Eleventy to turn them into a folder of static HTML, and serve that on the static-site setup. Covers the verified build and the honest choice between building locally and building on a server.

A blog is mostly text, so you don't want a database or a running app behind it — you want plain HTML that a web server can hand out instantly. Eleventy (11ty) is a static-site generator: you write posts in Markdown, run one command, and it produces a folder of finished HTML pages. This guide builds that blog, then covers the part most tutorials skip: where the build runs, and how the output gets onto Falix.

At a glance
You're building A Markdown blog compiled to static HTML by Eleventy
You need Node to run the build; the static-site setup to serve the output
Plan Any plan
Time About forty minutes

New to static hosting? Read Host a static website first — it's where the finished pages end up.

What you're building

Piece File
Build config .eleventy.js — input/output folders, a date filter
Layout src/_includes/base.njk — the HTML wrapper every page shares
Home page src/index.njk — lists your posts
Posts src/posts/*.md — one Markdown file per post
Output _site/ — the finished static site Eleventy generates

The files

package.json — Eleventy as a dev dependency, plus a build script:

{
  "name": "blog-eleventy",
  "version": "1.0.0",
  "private": true,
  "scripts": {
    "build": "eleventy"
  },
  "devDependencies": {
    "@11ty/eleventy": "^3.0.0"
  }
}

.eleventy.js — the configuration:

module.exports = function (eleventyConfig) {
  // Copy the stylesheet straight through to the output folder.
  eleventyConfig.addPassthroughCopy("src/style.css");

  // A tiny date filter so templates can print "2026-07-01".
  eleventyConfig.addFilter("date", (d) => new Date(d).toISOString().slice(0, 10));

  return {
    dir: { input: "src", includes: "_includes", output: "_site" },
    markdownTemplateEngine: "njk",
    htmlTemplateEngine: "njk",
  };
};

src/_includes/base.njk — the shared page wrapper:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>{{ title }}</title>
  <link rel="stylesheet" href="/style.css">
</head>
<body>
  <header><a href="/">My Blog</a></header>
  <main>{{ content | safe }}</main>
</body>
</html>

src/posts/posts.json — directory data that gives every post the layout and a shared tag (so they form a collection):

{
  "layout": "base.njk",
  "tags": "post"
}

src/index.njk — the home page, listing posts newest-first:

---
layout: base.njk
title: My Blog
---
<h1>My Blog</h1>
<ul>
{% for post in collections.post | reverse %}
  <li>
    <a href="{{ post.url }}">{{ post.data.title }}</a>
    <small>{{ post.date | date }}</small>
  </li>
{% endfor %}
</ul>

src/posts/hello-world.md — a post is just Markdown with a title and date:

---
title: Hello, world
date: 2026-07-01
---
# Hello, world

This is my first post, written in **Markdown**. Eleventy turns this file into
`/posts/hello-world/index.html` when it builds.

Add a src/style.css for looks, and drop in more .md files to add posts.

Build it

Eleventy runs on Node, so build it where Node lives — your own computer, or a Node server (more on that below). In the project folder:

npm install
npx @11ty/eleventy

You'll see it write the pages:

[11ty] Writing ./_site/index.html from ./src/index.njk
[11ty] Writing ./_site/posts/hello-world/index.html from ./src/posts/hello-world.md
[11ty] Copied 1 Wrote 3 files in 0.05 seconds (v3.1.6)

The _site/ folder now holds a complete static site — a home page that lists your posts, one HTML page per post, and your CSS copied across. That folder is everything you deploy.

🎯 Good to know: Everything in _site/ is plain HTML — no Node, no Eleventy, nothing running. Whatever serves it just needs to hand out files, which is exactly what the static-site setup does.

Get it onto Falix

Here's the honest part: Eleventy is a build tool (needs Node) and the static-site setup is a web server (nginx, no Node). They're two different jobs, so you have a choice about where the build happens.

Path A — build locally, upload the output (recommended)

  1. Run npx @11ty/eleventy on your computer.
  2. Deploy the static-site setup to a server.
  3. Upload the contents of _site/ into that server's public/ folder — drag them in the File Manager, or push over SFTP.
  4. Open your server's address. The blog is live.

This is the simplest and most reliable option: nginx serves finished files, there's no build to break on the server, and nothing of yours has to keep running.

Path B — build on a server with Git

Let Falix rebuild on every push, using Git deploy with a build step:

  • Connect your repo on the Git page and add a post-deploy command npx @11ty/eleventy (see Build steps).

  • The catch: the command runs where your server's application can run it. Eleventy needs Node, which the PHP Web Server (static-site) image doesn't have — so to build on the server you run it on a Node.js application and serve _site/ yourself with a tiny static server:

    const express = require('express');
    const app = express();
    app.use(express.static('_site'));
    const PORT = process.env.SERVER_PORT || 8080;
    app.listen(PORT, '0.0.0.0', () => console.log(`Listening on port ${PORT}`));

    Point the Main file at this index.js, add express to package.json, and set the build script to run on deploy. Now a git push rebuilds and serves in one step — at the cost of running a Node process instead of nginx.

Path A: build locally Path B: build on server
Runs on static-site (nginx) Node.js application
Server needs Node no yes
Rebuild on push manual re-upload automatic via Git
Best for simplest, most reliable frequent posts, hands-off

💡 Tip: Most blogs post rarely, so Path A is usually the right call — build when you write, upload once. Reach for Path B when you're pushing often and want it automated.

Make it yours

  • A real theme. Flesh out base.njk and style.css; Eleventy stays out of your way.
  • Tags and an archive. Eleventy builds collections from tags — add tag pages that list matching posts.
  • An RSS feed. Generate feed.xml from your posts collection so readers can subscribe.
  • Drafts. Give a post draft: true and filter it out of the collection until it's ready.

Everything past the Falix layer is standard Eleventy — the official docs at 11ty.dev cover layouts, collections, data, and plugins in full.

Troubleshooting

  • eleventy: not found — you didn't npm install first, or you're not in the project folder. Install, then use npx @11ty/eleventy.
  • Home page is blank / no posts listed — the posts aren't in the post collection. Check src/posts/posts.json sets "tags": "post" and your posts are in src/posts/.
  • A post shows raw Markdown — it's missing the layout. The posts.json above assigns base.njk to everything in the folder; make sure the file is there.
  • Deployed but 404 on the home page — after uploading, the web root must contain index.html directly (upload the contents of _site/, not the _site folder itself). See Host a static website.

Next steps

Was this guide helpful?