Skip to content

Build awesome plugins

Build awesome (powered by Eleventy) runs at build time when you publish your site. Plugins extend what the build can do — optimize images, generate sitemaps, add search, and more.

Two things to remember:

  • Plugins run during the build, not in the editor. You won't see their effects until you publish.
  • You customize the build in build.json. This file at the root of your repository is yours — Silex never overwrites it. The CI file (.gitlab-ci.yml) and the build script (build.sh) are generated by Silex; don't edit them.

How the build works

When you click Publish, this happens:

  1. Silex generates your site files (HTML, CSS, assets)
  2. Files are committed to your GitLab repository
  3. The .gitlab-ci.yml file triggers a CI/CD pipeline, which runs sh build.sh
  4. build.sh runs the steps listed in your build.json — the build awesome build (powered by Eleventy) plus any custom commands, applying plugins and optimizing assets
  5. The result (the _site/ folder) is deployed to GitLab Pages

The build.json file

build.json at the root of your repository lists the build steps in order. The default, created by Silex on first publish, is just the standard build:

[
  { "type": "build" }
]
  • { "type": "build" } — the standard Silex build (build awesome compiles public/ into _site/). It follows Silex updates automatically.
  • { "type": "sh", "value": "<shell command>" } — any shell command, before or after the build.

Silex never overwrites this file, so your customizations survive every publish. build.sh is regenerated from it at each publication — that's why you edit build.json, never build.sh or .gitlab-ci.yml.

Migrating from the old system

Before build.json, you customized the build by editing .gitlab-ci.yml and setting its first line to # silexOverwrite: false. Such files still work — Silex never touches them. To migrate: put your custom commands in a new build.json, set the first line of .gitlab-ci.yml back to # silexOverwrite: true, and publish. See Customize the build.

Adding a plugin: step by step

Let's walk through adding a plugin using image optimization as the example.

Step 1: Create a package.json

In your GitLab repository (at the root, next to build.json), create a package.json:

{
  "dependencies": {
    "@11ty/eleventy-img": "^1.0.0"
  }
}

Step 2: Create an eleventy.config.js

At the same level, create eleventy.config.js:

const Image = require("@11ty/eleventy-img");

module.exports = function (eleventyConfig) {
  eleventyConfig.addShortcode("image", async function (src, alt, widths = [300, 600], sizes = "100vh") {
    let metadata = await Image(src, {
      widths,
      formats: ["avif", "jpeg"],
    });

    let imageAttributes = {
      alt,
      sizes,
      loading: "lazy",
      decoding: "async",
    };

    return Image.generateHTML(metadata, imageAttributes);
  });
};

This generates avif and jpeg versions of your images at 300px and 600px widths.

Step 3: Update build.json

Add an npm i step before the build step in build.json (create the file at the root of your repository if it doesn't exist yet):

[
  { "type": "sh", "value": "npm i" },
  { "type": "build" }
]

The key change: npm i installs the dependencies from your package.json before the build runs. Don't touch .gitlab-ci.yml or build.sh — Silex generates them.

Image optimization with @11ty/eleventy-img

This is the most useful plugin for most sites. It transforms your images at build time to serve the smallest possible file to each visitor.

What it does

  • Generates multiple formats: avif, webp, jpeg, png, svg, gif
  • Generates multiple sizes from a single source image
  • Never upscales beyond the original dimensions
  • Adds proper width and height attributes to reduce layout shift
  • Fetches and caches remote images locally

Instead of using shortcodes, you can let the plugin process all <img> tags automatically:

import { eleventyImageTransformPlugin } from "@11ty/eleventy-img";

export default function (eleventyConfig) {
  eleventyConfig.addPlugin(eleventyImageTransformPlugin, {
    formats: ["avif", "webp", "jpeg"],
    widths: ["auto"],
    htmlOptions: {
      imgAttributes: {
        loading: "lazy",
        decoding: "async",
      },
    },
  });
};

This is the simplest approach for Silex sites — every image you add in the editor gets optimized automatically during the build.

Per-image overrides

You can control optimization per image using HTML attributes (in the Element settings (gear icon)):

  • eleventy:widths="200,600" — generate specific widths
  • eleventy:formats="webp" — use specific formats only
  • eleventy:ignore — skip this image entirely

Build performance tips

Image optimization adds build time. To keep builds fast:

  1. Limit formats. avif produces the smallest files but is the slowest to generate. Start with ["webp", "jpeg"] and add avif only if you need it.
  2. Use "auto" for widths unless you know you need specific sizes.
  3. Cache remote images. If your images come from a CMS, preserve the .cache folder between builds to avoid re-fetching.

Other useful plugins

Adds full-text search to your published site. Users can search across all pages without a server.

Sitemap

Generates an XML sitemap (sitemap.xml) that search engines use to discover your pages. Essential for SEO.

Pagination / Pagebreak

Splits long content across multiple physical pages with prev/next navigation. Different from collection pages, which generate one page per data item.

RSS

Generates an RSS feed so visitors can subscribe to your content. Useful for blogs.

eleventy-plugin-concat

A Silex Labs plugin that concatenates multiple CSS and JavaScript files into single files, reducing HTTP requests.

Common mistakes

  • Editing .gitlab-ci.yml or build.sh instead of build.json. Those files are generated by Silex and your changes are overwritten on next publish. Only build.json is yours.
  • Forgetting the npm i step in build.json. Without it, your package.json dependencies are not installed and the build uses no plugins.
  • Adding too many image formats. Each format multiplied by each width multiplied by each image adds up. Start small.
  • Not testing the build. After changing build.json, publish and check the pipeline in GitLab (CI/CD → Pipelines) to see if it succeeds — or run sh build.sh locally in a clone of your repository.

Learn more


Quiz

Q1: You added your custom command to build.sh, but after publishing it was gone. What happened?

  • A) The command was not compatible
  • B) build.sh is generated by Silex — customizations belong in build.json
  • C) You forgot to run npm i
Answer

B) build.sh is generated by Silex — it is regenerated from build.json at every publish, and so is the CI file. Put your custom steps in build.json: Silex never overwrites that file.

Q2: You want all images on your site optimized automatically without changing your Silex design. Which approach should you use?

  • A) The shortcode approach — add shortcodes to each image
  • B) The HTML transform approach — it processes all img tags automatically
  • C) Manually optimize images before uploading
Answer

B) The HTML transform approach — it automatically processes every <img> tag in the build output. No changes needed in the editor.

Q3: Your build is slow. You're generating avif, webp, jpeg, and png for 5 different widths. What should you try first?

  • A) Reduce the number of formats — drop avif and png
  • B) Add more build minutes to GitLab
  • C) Use smaller source images
Answer

A) Reduce the number of formats — avif is the slowest to generate. Start with webp + jpeg and only add avif if you need the extra compression.

Q4: What file do you need to create to add plugin dependencies?

  • A) plugins.json
  • B) package.json
  • C) .eleventy.js
Answer

B) package.json — this is the standard Node.js dependency file. An npm i step in build.json installs the packages listed in it.

Q5: What's the difference between the Pagebreak plugin and collection pages?

  • A) No difference, they do the same thing
  • B) Pagebreak splits one design across multiple pages; collection pages generate one page per data item
  • C) Collection pages are for blogs, Pagebreak is for e-commerce
Answer

B) Pagebreak splits one design across multiple pages; collection pages generate one page per data item — they serve different purposes. Pagebreak is for long content, collection pages are for dynamic data.

Edit this page on GitLab