Setting up 11ty with Decap CMS and Vite: A developer's journey
Explore building a high-performance website with 11ty, Decap CMS, and Vite, leveraging JAMstack for speed and scalability in static site development.

Introduction
As a web developer with experience in various technologies, I have embraced the JAMstack architecture for its simplicity, performance, and scalability. In this article, I'll walk you through my experience setting up a project using 11ty (Eleventy), Decap CMS, and Vite, all hosted on Netlify for continuous deployment.
Why this stack?
This stack is ideal for static, content-driven websites such as product pages, landing pages, news articles, documentation, portfolios, and blogs with infrequent updates. It excels in scenarios where dynamic functionality (like user accounts or real-time updates) is unnecessary, offering exceptional performance, low hosting costs, and a streamlined content management experience. Furthermore it enables a CI/CD pipeline where Git updates automatically trigger production builds.
There are many Static Site Generators available for JAMstack projects, including Next.js, Hugo, Gatsby, and Jekyll. I chose 11ty for its simplicity, flexibility, and performance. Now in version 3.0, it has been trusted by organizations like NASA, CERN, Mozilla, and the W3C. It supports multiple templating languages such as Markdown, Nunjucks, Liquid, and Handlebars making it incredibly versatile. Its barebones nature makes it perfect for small and simple projects, offering unmatched speed and flexibility.
I opted for Decap CMS (formerly Netlify CMS) because it's a Git-based CMS that aligns perfectly with the static site philosophy of 11ty. It's free, open-source, and licensed under MIT. As a Git-based CMS, it seamlessly integrates with Git-based CI/CD workflows. The fact that it's specifically designed to work well with Netlify makes it an obvious choice for this setup.
Finally, I chose Vite because it's one of the fastest module bundlers available, offering blazing-fast development and build times. Vite also allows me to use modern JavaScript imports and organize my files efficiently.
Setting up 11ty
Step 1: Creating the project
Start by creating a new directory for your project and initializing npm:
mkdir eleventy-project
cd eleventy-project
npm init -y
Step 2: Installing 11ty
Next, install Eleventy:
npm install @11ty/eleventy
Step 3: Installing additional packages:
- Vite plugin for 11ty: Integrates Vite with Eleventy for modern asset bundling.
npm install @11ty/eleventy-plugin-vite@alpha --save-dev - SEO plugin: Automatically generates meta tags for better SEO.
npm install eleventy-plugin-seo --save - YAML parser: Enables YAML files as a data source in
_data.npm install js-yaml
Step 4: Project structure
Organize your project with the following directory structure:
eleventy-project
┣ src
┃ ┣ _data
┃ ┣ _includes
┃ ┃ ┣ layouts
┃ ┃ ┗ partials
┃ ┣ admin
┃ ┃ ┣ config.yml
┃ ┃ ┗ index.html
┃ ┣ assets
┃ ┃ ┣ scripts
┃ ┃ ┣ styles
┃ ┃ ┣ uploads
┃ ┃ ┗ favicon.ico
┃ ┣ index.html
┃ ┗ sitemap.xml
┣ eleventy.config.js
┗ package.json
- _data: Stores global data files accessible across templates (e.g., YAML, JSON).
- _includes:
- layouts: Reusable page layouts.
- partials: Smaller reusable code snippets (e.g., headers, footers).
- admin: Decap CMS files, including
config.ymland its frontend interface. - assets: Holds styles, scripts, media, and favicon.
- index.html: Homepage with front matter for layout and SEO configuration.
- sitemap.xml: Sitemap for search engines.
- eleventy.config.js: Main configuration file for Eleventy.
Step 5: Configuring 11ty (eleventy.config.js)
Here's the configuration file with necessary settings for this setup:
const yaml = require("js-yaml");
const pluginSEO = require("eleventy-plugin-seo");
module.exports = async function (eleventyConfig) {
// Enable YAML files as data
eleventyConfig.addDataExtension("yml", (contents) => yaml.load(contents));
// Add Vite plugin for asset bundling
const EleventyPluginVite = (await import("@11ty/eleventy-plugin-vite")).default;
eleventyConfig.addPlugin(EleventyPluginVite, {
viteOptions: {
build: {
rollupOptions: {
output: {
assetFileNames: (assetInfo) => {
const extType = assetInfo.name.split('.').pop();
if (['js', 'mjs'].includes(extType)) {
return 'assets/scripts/[name]-[hash][extname]';
} else if (['css'].includes(extType)) {
return 'assets/styles/[name]-[hash][extname]';
} else if (['png', 'jpg', 'svg', 'gif', 'pdf'].includes(extType)) {
return 'assets/uploads/[name]-[hash][extname]';
}
return 'assets/[name]-[hash][extname]';
},
chunkFileNames: 'assets/scripts/[name].[hash].js',
entryFileNames: 'assets/scripts/[name].[hash].js',
},
},
}
}
});
// Add SEO plugin for meta tag generation
eleventyConfig.addPlugin(pluginSEO, require("./src/_data/seo.json"));
// Passthrough copy for static files
eleventyConfig.addPassthroughCopy("src/sitemap.xml");
eleventyConfig.addPassthroughCopy("src/assets/");
eleventyConfig.addPassthroughCopy("src/admin/");
// Watch assets for changes during development
eleventyConfig.addWatchTarget("src/assets/");
eleventyConfig.addWatchTarget("src/admin/");
return {
dir: {
input: "src",
output: "_site",
includes: "_includes",
data: "_data",
layouts: "_includes/layouts",
},
templateFormats: ['md', 'njk', 'html'],
markdownTemplateEngine: "njk",
htmlTemplateEngine: "njk",
dataTemplateEngine: "njk",
};
};
This configuration:
- Enables YAML for _data files.
- Integrates Vite for fast development and optimized builds.
- Registers the SEO plugin with 11ty.
- Specifies the directory structure for Eleventy to process files.
- Share this page