---
title: 'Integrate with Eleventy Base Blog'
description: 'Add @apleasantview/eleventy-plugin-baseline to eleventy-base-blog: install, wire config, align data and assets, migrate head extras, and verify the build.'
slug: 'integrate-eleventy-base-blog'
type: 'article'
date: 2026-01-25T00:00:00.000Z
lang: 'en'
url: 'https://www.eleventy-baseline.dev/docs/how-to/integrate-eleventy-base-blog/'
---

{% alertBlock "info" %}

This article is planned for revision, its content might be stale.

{% endalertBlock %}

Add Baseline to the official `eleventy-base-blog` starter with as little disruption as the starter's existing wiring allows. The work splits into four pieces: bring Baseline in, line the starter's directories up with Baseline's contract, migrate the starter's hand-rolled `<head>` into Baseline's head pipeline, and confirm the output.

If you don't already have a project to integrate into, the [[simple-baseline-site | simple site tutorial]] is the lighter starting point.

---

## Prerequisites

- You have `eleventy-base-blog` cloned and running (`npm install`, `npm run dev` works).
- Eleventy 3.x; `package.json` has `dev` and `build` scripts.
- `settings.url` will be set via env (`URL`) for production.

---

## 1) Install Baseline

```bash
npm install @apleasantview/eleventy-plugin-baseline
```

---

## 2) Wire Baseline into `eleventy.config.js`

In your existing config:

{% stepsBlock "compact" %}

- Remove the `HtmlBasePlugin` import and call. Baseline registers its own.

- Import Baseline and the Baseline directory contract; add the plugin last so it sees the rest of your config:

  ```js
  import baseline, { config as baselineConfig } from '@apleasantview/eleventy-plugin-baseline';
  import settings from './src/_data/settings.js';

  export default async function (eleventyConfig) {
  	// ...your existing config

  	await eleventyConfig.addPlugin(baseline(settings));
  }

  export const config = baselineConfig; // spread to override if needed
  ```

- Update `passthroughCopy` inputs to `./src/static/` and `./src/content/feed/pretty-atom-feed.xsl`.

- Remove watch targets for CSS or images if present (Baseline handles them).

- Point CSS and JS bundle `toFileDirectory` to `assets/css` and `assets/js` respectively.

- Set `base` to `process.env.URL`.

{% endstepsBlock %}

The full file is in the [`eleventy-base-blog` fork](https://github.com/apleasantview/eleventy-baseline-blog/blob/baseline-edition/eleventy.config.js).

---

## 3) Add a local `.env` for development

```txt
ELEVENTY_ENV="development"
URL="http://localhost:8080"
```

In CI and production, set `URL` to your live origin (e.g. `https://www.example.com`); Baseline uses it for canonical URLs and the sitemap.

---

## 4) Move Eleventy Base Blog folders under `src/`

Move the following folders to match Baseline's defaults:

- `_data` → `src/_data`
- `_includes` → `src/_includes`
- `content` → `src/content`
- `css` → `src/assets/css`
- `public` → `src/static`

The last move has an asymmetry worth knowing upfront. Baseline's directory contract sets `public: 'static'`, so the virtual key on `eleventyConfig.directories` is `public` but the folder on disk stays `static/`. The [[config-export | config-export reference]] covers the same split.

Update layouts and includes to resolve from `src/`, and content from `src/content/`. Delete `sitemap.xml.njk` in `src/content/`; Baseline's sitemap module handles it.

---

## 5) Add the required data file

`src/_data/settings.js` is the single source for site identity and head extras. The starter's `_data/head.js` is no longer in play once Baseline is wired; head extras move onto `settings.head` instead (step 7 walks through the migration):

```js
export default {
	title: 'Eleventy Base Blog (Baseline Edition)',
	tagline: 'Baseline + Eleventy Base Blog',
	url: process.env.URL || 'http://localhost:8080/',
	defaultLanguage: 'en',
	noindex: false,

	head: {
		link: [{ rel: 'stylesheet', href: '/assets/css/index.css' }],
		script: [{ src: '/assets/js/index.js', defer: true }]
	}
};
```

---

## 6) Align assets

Make sure these exist (or create minimal stubs):

- `src/assets/css/index.css`: import your base CSS or start empty.
- `src/assets/js/index.js`: optional JS entry; can be empty.
- `src/assets/assets.11tydata.js` to keep the assets directory out of collections:
  ```js
  export default {
  	eleventyExcludeFromCollections: true
  };
  ```

---

## 7) Migrate the starter's head children

The starter's `base.njk` writes a `<head>` with three extras Baseline does not render for you: an Atom feed `<link>`, an inline `<style>` produced by `eleventy-plugin-bundle`, and a `@zachleat/heading-anchors` `<script type="module">`.

With Baseline, you do not author your own `<head>`; you push these into the head pipeline. One pattern per extra, in the same order:

{% stepsBlock %}

**Atom feed link → `settings.head.link[]`.** Site-wide static link. Add it to `src/_data/settings.js`:

```js
head: {
	link: [
		{ rel: 'stylesheet', href: '/assets/css/index.css' },
		{
			rel: 'alternate',
			type: 'application/atom+xml',
			title: 'Eleventy Base Blog',
			href: '/feed/feed.xml'
		}
	];
}
```

<br>

**`@zachleat/heading-anchors` script → `settings.head.script[]` plus an entry point.** Re-export the module from a small entry under `src/assets/js/heading-anchors/index.js`:

```js
import '@zachleat/heading-anchors';
```

Baseline's assets pipeline bundles it to `dist/assets/js/heading-anchors/index.js`. Reference it in head extras:

```js
script: [
	{ src: '/assets/js/index.js', defer: true },
	{ src: '/assets/js/heading-anchors/index.js', type: 'module' }
];
```

<br>

**Per-page bundled CSS → `getBundle("css")` style block.** This is the non-trivial migration. The starter collects per-page CSS through `eleventy-plugin-bundle` and inlines the result. Baseline has no head-extras shape for inline `<style>`, so two approaches work depending on what the bundle is for:

- **If the styles are page-specific and small**, keep the bundle plugin and inline them from the layout body (after `<baseline-head>`), with the small caveat that they sit outside the `<head>`. Most browsers handle this fine, but it's not strictly compliant.
- **If the styles are reusable**, consolidate them into files under `src/assets/css/` and inline with Baseline's `inlinePostCSS` filter, called inside an inlineable head fragment that the layout includes:

  {% raw %}

  ```nunjucks
  {% set cssPath = _baseline.paths.assets ~ "css/post.css" %}
  {{ cssPath | inlinePostCSS | safe }}
  ```

  {% endraw %}

  This belongs at the top of the layout body, not inside `<baseline-head>` (which Baseline replaces wholesale). The placeholder is your `<head>`; everything else goes in the body.

{% endstepsBlock %}

---

## 8) Add `<baseline-head>` to `base.njk`

The placeholder sits inside `<html>`, as a sibling of `<body>`. Baseline replaces it with the rendered `<head>` element at build time. Don't author your own `<head>` around it:

{% raw %}

```nunjucks
<!DOCTYPE html>
<html lang="en">
  <baseline-head></baseline-head>
  <body>
    ...
  </body>
</html>
```

{% endraw %}

---

## 9) Organise content and set permalinks.

Move the following files to `src/content/pages/` and set their permalinks as needed:

- `404.md`, `about.md`, `blog.njk`, `index.njk`, `tag-pages.njk`, `tags.njk`

Example `index.njk`:

{% raw %}

```nunjucks
---js
const permalink = "/";
---
```

{% endraw %}

Add the permalink function in `blog.11tydata.js`:

```js
export default {
	// Keep tags and layout keys.
	permalink: function ({ page }) {
		if (page.inputPath.includes('11tydata.js')) {
			return false;
		}
		return `/blog/${this.slugify(page.fileSlug)}/`;
	}
};
```

---

## 10) Use Baseline's inline-asset filters where it makes sense.

    Replace direct CSS link-tags in `src/_includes/layouts/post.njk` and `src/_includes/layouts/home.njk` with the inline PostCSS filter. `_baseline.paths.assets` resolves to your assets input directory:

    {% raw %}

    ```nunjucks
    {% set cssPath = _baseline.paths.assets ~ "css/message-box.css" %}
    {{ cssPath | inlinePostCSS | safe }}
    ```

    {% endraw %}

---

## 11) Verify head, meta, and sitemap.

    - Dev: `npx rimraf dist/ && npm run dev`
    - Build: `npx rimraf dist/ && npm run build`
    - Check a page's `<head>` for `<title>`, `<meta name="description">`, `<link rel="canonical">`, and (if multilingual) hreflang alternates.
    - Inspect `dist/sitemap.xml` for correct URLs (uses `settings.url` and `pathPrefix` if set).

---

## 12) Optional: navigator and debug filters.

    - Set `navigator: true` in the plugin options if you want the navigator page (dev only).
    - Use the `_inspect`, `_json`, and `_keys` filters on a debug page to inspect data.

---

## Next steps

- Add recommended build scripts and helper packages: [[build-scripts-and-cleanup | Build Scripts and Cleanup]].

---

## Notes

- Keep `settings.url` origin-only; use `pathPrefix` if you deploy under a subpath.
- Baseline's assets pipeline uses `src/assets/css/index.css` and `src/assets/js/index.js` as the default entry points.
- If you have other CSS or JS paths, either point `settings.head.link[]` and `settings.head.script[]` at the Baseline output paths or mirror the files into `src/assets/`.

---

## See also

- [[config-export | Config export reference]]
- [[assets | Assets module]]
- [[head | Head module]]
- [[navigator | Navigator module]]
