Stand with Ukraine 🇺🇦
Eleventy
The possum is Eleventy’s mascot

Eleventy Documentation

Menu

Eleventy Edge Coming soon in v2.0.0 Jump to heading

A plugin to run Eleventy in an Edge Function to add dynamic content to your Eleventy sites.

This feature is considered experimental and requires Eleventy v2.0.0-canary.7 or higher. Our first release is limited to Netlify Edge Functions support only.

Eleventy Edge is an exciting new way to add dynamic content to your Eleventy templates. With a simple Eleventy shortcode you can opt-in a part of your Eleventy template to run on an Edge server, allowing your site to use dynamic, user-specific content!

Here are a few ideas:

Contents Jump to heading

Try out the demos Jump to heading

How does it work? Jump to heading

If you don’t yet have an Eleventy project, go through the Getting Started Guide first and come back here when you’re done!

1. Installation Jump to heading

The Eleventy Edge plugin is bundled with Eleventy, but do note that the plugin requires version 2.0.0-canary.7 or newer.

At time of initial launch, you will need to use Netlify CLI to run Eleventy Edge locally (netlify-cli version 10.0.0 or higher).

npm install netlify-cli

2. Add to your configuration file Jump to heading

Filename .eleventy.js
const { EleventyEdgePlugin } = require("@11ty/eleventy");

module.exports = function(eleventyConfig) {
eleventyConfig.addPlugin(EleventyEdgePlugin);
};
Expand to read about the advanced options (you probably don’t need these)
const { EleventyEdgePlugin } = require("@11ty/eleventy");

module.exports = function(eleventyConfig) {
eleventyConfig.addPlugin(EleventyEdgePlugin, {
// controls the shortcode name
name: "edge",

// Used for the default deno import URL
// Added in 2.0.0-canary.7
eleventyEdgeVersion: "1.0.0",

// Version check for the Edge runtime
compatibility: ">=2",

// controls where the Edge Function bundles go
functionsDir: "./netlify/edge-functions/",

// Directory to write the import_map.json to
// Also supported: `false`
// Added in 2.0.0-canary.7
importMap: "./.netlify/edge-functions/",
});
};

Starting with Eleventy 2.0.0-canary.7 the above plugin will automatically generate an Eleventy Edge Function file for you at: ./netlify/edge-functions/eleventy-edge.js.

Expand to see a sample Eleventy Edge Function

Note that Edge Functions run in Deno so they require ESM (import not require).

import { EleventyEdge } from "eleventy:edge";
import precompiledAppData from "./_generated/eleventy-edge-app-data.js";

export default async (request, context) => {
try {
let edge = new EleventyEdge("edge", {
request,
context,
precompiled: precompiledAppData,

// default is [], add more keys to opt-in e.g. ["appearance", "username"]
cookies: [],
});

edge.config(eleventyConfig => {
// Run some more Edge-specific configuration
// e.g. Add a sample filter
eleventyConfig.addFilter("json", obj => JSON.stringify(obj, null, 2));
});

return await edge.handleResponse();
} catch(e) {
console.log( "ERROR", { e } );
return context.next(e);
}
};
Expand to read a warning about Edge on Eleventy 2.0.0-canary.6
If you tried Eleventy Edge on 2.0.0-canary.6, unfortunately we had to restructure some deps and the Edge Function import URLs are different starting with 2.0.0-canary.7. The good news is that Eleventy will generate a working file for you! Sorry folks!

Read more about Netlify’s Edge Functions Jump to heading

3. Additions to .gitignore Jump to heading

# Netlify generated stuff
.netlify/

# Eleventy Edge Build Data files
netlify/edge-functions/_generated

4. netlify.toml Jump to heading

If you don’t already have a netlify.toml, expand this to view a sample starter.
Filename netlify.toml
[dev]
framework = "#static"
command = "npx @11ty/eleventy --quiet --watch"

[build]
command = "npx @11ty/eleventy"
publish = "_site"

Add this to your netlify.toml file.

Filename netlify.toml
[[edge_functions]]
function = "eleventy-edge"
path = "/*"

eleventy-edge points to the file that was created above at ./netlify/edge-functions/eleventy-edge.js. Using path= "/*" will run Eleventy Edge on all of the pages on your site. You can change this setting to something more granular (e.g. path = "/" for just the home page).

5. Make your content template Jump to heading

Here we are making a simple template file. We can use the {% edge %} shortcode to run the Liquid template syntax inside on the Edge server.

View this example in: Liquid Nunjucks 11ty.js
Filename index.liquid
The content outside of the `edge` shortcode is generated with the Build.

{% edge %}
The content inside of the `edge` shortcode is generated on the Edge.

<pre>
{{ eleventy | json }}
</pre>
{% endedge %}
Filename index.njk
The content outside of the `edge` shortcode is generated with the Build.

{% edge %}
The content inside of the `edge` shortcode is generated on the Edge.

<pre>
{{ eleventy | dump(2) }}
</pre>
{% endedge %}
Filename index.11ty.js
module.exports = async function(data) {
return `The content outside of the \`edge\` shortcode is generated with the Build.

${await this.edge(`The content inside of this.edge() is generated on the Edge.
<pre>
{{ eleventy | json }}
</pre>, "liquid")}
`
;
};

As documented in Limitations, we are using liquid here because 11ty.js is not yet supported as an Edge content target.

Learn more about the edge shortcode.

6. Run your local server Jump to heading

npx netlify dev

Navigation to index.liquid by going to http://localhost:8888/ in your browser. (Double check your console output to make sure the port is 8888).

Learn More Jump to heading

Always Escape Input Jump to heading

When using any dynamic user input (via query parameters or cookies), the values here should be treated as potentially malicious user input and you must escape these if you use them in templates. The way to do this is template language specific.

edge shortcode examples Jump to heading

Changing the Template Language of the edge Content Jump to heading

In what might feel familiar to folks that have used the Render plugin, adding an additional argument to the edge shortcode allows you to change the content’s template language. If no argument is specified, it uses the template syntax of the parent template.

If you use the edge shortcode inside of a layout file, it’s best to explicitly specify the template language!
View this example in: Liquid Nunjucks 11ty.js
Filename index.liquid
{% edge "md" %}
# Markdown Heading
{% endedge %}
Filename index.njk
{% edge "md" %}
# Markdown Heading
{% endedge %}
Filename index.11ty.js
module.exports = async function(data) {
return `
${await this.edge("# Markdown heading", "md")}
`
;
};

Passing Build-time Data to your Edge Function Jump to heading

Edge content is a separate template, processed and built on the Edge. As such it has no access to your build’s data cascade. However, you can pass data in to be re-used!

When the build data argument is a literal (a string or number), it is mapped to _ in the template.

View this example in: Liquid Nunjucks 11ty.js
Filename index.liquid
---
name: Zach
---
{% edge "liquid,md" name %}
# Markdown heading for {{ _ }}
{% endedge %}
Filename index.njk
---
name: Zach
---
{% edge "liquid,md", name %}
# Markdown heading for {{ _ }}
{% endedge %}
Filename index.11ty.js
module.exports.data = {
name: "Zach",
};

module.exports.render = async function(data) {
return `
${await this.edge("# Markdown heading for {{ _ }}", "liquid,md", data.name)}
`
;
};

When the build data argument is an object, the object properties are available as top-level globals in the template.

View this example in: Liquid Nunjucks 11ty.js
Filename index.liquid
---
buildData:
name: Zach
---
{% edge "liquid,md" buildData %}
# Markdown heading for {{ name }}
{% endedge %}
Filename index.njk
---
buildData:
name: Zach
---
{% edge "liquid,md", buildData %}
# Markdown heading for {{ name }}
{% endedge %}
Filename index.11ty.js
module.exports.data = {
buildData: {
name: "Zach"
}
};

module.exports.render = async function(data) {
return `
${await this.edge("# Markdown heading for {{ name }}", "liquid,md", data.buildData)}
`
;
};

Add Global Data to your Edge Function Jump to heading

If you open up your generated netlify/edge-functions/eleventy-edge.js file, you’ll notice that you are able to run your own arbitrary configuration code on Edge. This means you can run eleventyConfig.addGlobalData to add your own global data to the edge templates Coming soon in v2.0.0-canary.11. Any data you add here will automatically be available as a global inside of any {% edge %} shortcodes without having to pass it as an argument.

Filename netlify/edge-functions/eleventy-edge.js
 import { EleventyEdge } from "eleventy:edge";
import precompiledAppData from "./_generated/eleventy-edge-app-data.js";
+import searchData from "./_generated/search-data.js";

export default async (request, context) => {
try {
let edge = new EleventyEdge("edge", {
request,
context,
precompiled: precompiledAppData,
});

edge.config((eleventyConfig) => {
+ eleventyConfig.addGlobalData("search", searchData);
});

return await edge.handleResponse();
} catch (e) {
console.log("ERROR", { e });
return context.next(e);
}
};

Notably, the above adds a search global from a file we’ve created to populate search data. Now we can reference it in our templates like so:

View this example in: Liquid Nunjucks 11ty.js
Filename index.liquid
{% edge "liquid" %}
{{ search | json }}
{% endedge %}
Filename index.njk
{% edge "liquid" %}
{{ search | json }}
{% endedge %}
Filename index.11ty.js
module.exports.render = async function(data) {
return `
${await this.edge("{{ search | json }}", "liquid")}
`
;
};

Frequently Asked Questions Jump to heading

Limitations Jump to heading

How does it compare to Serverless? Jump to heading

They can be used together! Eleventy Edge can be used to process both serverless and build templates. Keep in mind that Edge functions are not cached so if you want to use them with Serverless, you’ll likely get the most value out pairing with On-demand Builders.


Other pages in Plugins: