| title | Plugins |
|---|---|
| layout | default |
| permalink | /plugins/ |
| description | Using and configuring plugins to extend GenGen functionality |
| nav_section | Advanced Features |
| nav_order | 2 |
GenGen uses a powerful plugin system to extend functionality. Plugins can be configured through your site's configuration file, and you can enable/disable them individually or by groups.
Plugins are configured in your config.yaml file under the plugins section:
plugins:
enabled:
- core # Enable the core plugin group
- seo # Enable SEO plugins
disabled:
- TailwindPlugin # Disable a specific pluginGenGen organizes plugins into logical groups for easier management:
{% for group in site.data.plugins.groups %} {% assign group_key = group[0] %} {% assign group_data = group[1] %}
- {{ group_key }}: {{ group_data.description }} {% endfor %}
By default, GenGen enables only the core group:
plugins:
enabled:
{% for group in site.data.plugins.defaults.enabled %} - {{ group }}
{% endfor %}
disabled: {{ site.data.plugins.defaults.disabled | jsonify }}
groups:
{% for group in site.data.plugins.groups %}{% assign group_data = group[1] %} {{ group[0] }}:
{% for plugin in group_data.plugins %} - {{ plugin.class_name }}
{% endfor %}
{% endfor %}{% for example in site.data.plugins.examples %} {% assign example_data = example[1] %} {{ example_data.description }}:
{{ example_data.config | jsonify }}{% endfor %}
Safe mode disables Lua plugins unless they are explicitly allowlisted.
safe: true
safe_plugins:
- "site-enhancer"
- "theme-banner"You can also enable safe mode from the CLI:
gengen build --safePlugins can include a _data/ directory inside the plugin folder. These files
are merged into site.data at build time. Precedence is:
site _data → theme _data → plugin _data.
GenGen comes with several built-in plugins that provide core functionality:
{% for group in site.data.plugins.groups %} {% assign group_data = group[1] %}
{{ group_data.description }}
{% for plugin in group_data.plugins %}
{{ plugin.description }}
{% if plugin.config_key %}Default configuration:
{{ plugin.config_key }}:
{{ plugin.default_config | jsonify }}{% endif %}
{% if plugin.supported_extensions %}Supported file extensions:
{% for ext in plugin.supported_extensions %}- {{ ext }}
{% endfor %}
{% endif %}
{% if plugin.features %}Features: {% for feature in plugin.features %}- {{ feature }} {% endfor %} {% endif %}
{% if plugin.available_objects %}Available objects:
{% for obj in plugin.available_objects %}- {{ obj }}
{% endfor %}
{% endif %}
{% if plugin.requirements %}Requirements: {% for req in plugin.requirements %}- {{ req }} {% endfor %} {% endif %}
{% if plugin.usage %}Usage: {{ plugin.usage }} {% endif %}
{% endfor %} {% endfor %}
GenGen provides a command-line interface for managing plugins:
# {{ site.data.plugins.commands.list | split: ' ' | slice: 2, 10 | join: ' ' }}
{{ site.data.plugins.commands.list }}
# {{ site.data.plugins.commands.available | split: ' ' | slice: 2, 10 | join: ' ' }}
{{ site.data.plugins.commands.available }}
# {{ site.data.plugins.commands.enabled | split: ' ' | slice: 2, 10 | join: ' ' }}
{{ site.data.plugins.commands.enabled }}
# {{ site.data.plugins.commands.groups | split: ' ' | slice: 2, 10 | join: ' ' }}
{{ site.data.plugins.commands.groups }}Here are some common configuration patterns:
{% for example in site.data.config_examples %} {% assign example_data = example[1] %}
{{ example_data.description }}
{{ example_data.config }}{% endfor %}
GenGen custom plugins are Lua-based and auto-discovered. Each plugin lives in its
own directory with a config.yaml and a Lua entrypoint.
Legacy Dart-based plugins are still discovered but will log warnings during load. New plugins should use Lua.
GenGen loads plugins from two locations:
- Site plugins:
<site>/_plugins/<plugin>/ - Theme plugins:
<site>/_themes/<theme>/_plugins/<plugin>/
You can customize the site plugins folder with plugin_dir in config.yaml
(default: _plugins).
_plugins/
my-plugin/
config.yaml
main.lua
assets/
banner.css
_themes/
default/
_plugins/
theme-banner/
config.yaml
main.lua
theme.css
{% include docs_reference_table.html scope=site.data.lua_plugins.config_fields %}
Example with explicit files:
name: site-enhancer
entrypoint: main.lua:init_plugin
description: Adds a callout and writes extra output.
files:
- name: styles
path: "assets/*.css"
- name: banner
path: "images/banner.png"If files is omitted, GenGen scans the plugin directory and registers all files.
Non-Lua files are copied to /assets/plugins/<plugin-name>/.
_plugins/my-plugin/config.yaml:
name: my-plugin
entrypoint: main.lua:init_plugin
description: A custom plugin for GenGen
author: Your Name
version: 1.0.0_plugins/my-plugin/main.lua:
function init_plugin(metadata)
return {
head_injection = '<meta name="my-plugin" content="enabled">',
css_assets = { 'assets/styles.css' },
convert = function(content, page)
return '<div class="plugin-callout">Injected by Lua</div>\n' .. content
end,
after_generate = function()
gengen.content.write_site('assets/my-plugin.txt', 'Generated by my-plugin')
end
}
end_themes/default/_plugins/theme-banner/config.yaml:
name: theme-banner
entrypoint: main.lua:init_plugin
description: Theme-level badge and CSS._themes/default/_plugins/theme-banner/main.lua:
function init_plugin(metadata)
return {
css_assets = { 'theme.css' },
body_injection = '<div class="plugin-pill">Theme plugin active</div>'
}
endAll hook names are snake_case. Missing hooks are treated as no-ops.
{% include docs_reference_table.html scope=site.data.lua_plugins.hooks.lifecycle %}
{% include docs_reference_table.html scope=site.data.lua_plugins.hooks.convert %}
{% include docs_reference_table.html scope=site.data.lua_plugins.hooks.assets %}
Asset paths are relative to the plugin directory and are served at
/assets/plugins/<plugin-name>/<asset-path>.
{% include docs_reference_table.html scope=site.data.lua_plugins.hooks.liquid %}
Filters receive (value, args, named_args) and return the transformed value.
liquid_filters = {
shout = function(value, args, named)
return string.upper(tostring(value))
end
}The page argument is a plain Lua table derived from the internal document model.
{% include docs_reference_table.html scope=site.data.lua_plugins.page_object %}
GenGen exposes a standard library inside Lua plugins:
{% include docs_reference_table.html scope=site.data.lua_plugins.stdlib.log %}
{% include docs_reference_table.html scope=site.data.lua_plugins.stdlib.config %}
{% include docs_reference_table.html scope=site.data.lua_plugins.stdlib.paths %}
{% include docs_reference_table.html scope=site.data.lua_plugins.stdlib.content %}
{% include docs_reference_table.html scope=site.data.lua_plugins.stdlib.util %}
{% include docs_reference_table.html scope=site.data.lua_plugins.stdlib.plugin %}
Plugins run in discovery order: site plugins first, then theme plugins. Conversion hooks run after Liquid renders content and before layout rendering.
To enable automatic asset injection in your templates:
<!DOCTYPE html>
<html>
<head>
<title>{{ page.title }}</title>
<!-- Plugin assets will be automatically injected here -->
{% plugin_head %}
</head>
<body>
{{ content }}
<!-- Plugin body assets will be automatically injected here -->
{% plugin_body %}
</body>
</html>{% plugin_head %} injects head_injection, CSS assets, and meta tags from plugins.
{% plugin_body %} injects body_injection and JavaScript assets.
- Use plugin groups: Organize related plugins into logical groups
- Start with core: Always enable at least the core plugin group
- Test configurations: Verify your plugin configuration works as expected
- Monitor performance: Some plugins may impact build times
- Keep plugins updated: Ensure custom plugins work with GenGen updates
- Document dependencies: Clearly document any external tool requirements
Plugin not loading:
- Check that the plugin name is spelled correctly
- Verify the plugin is in the enabled list or group
- Ensure the plugin isn't in the disabled list
Build errors:
- Check plugin configuration syntax
- Verify external tool dependencies (e.g., Tailwind CSS executable)
- Review plugin-specific configuration options
Performance issues:
- Disable unnecessary plugins
- Check for plugin conflicts
- Monitor build times with different plugin combinations
# Check current plugin status
gengen plugins
# Build with verbose logging
gengen build --verbose
# Check site configuration
gengen dumpWhen contributing plugins to GenGen:
- Follow the established plugin structure
- Include comprehensive documentation
- Add appropriate tests
- Consider plugin groups and categorization
- Ensure compatibility with existing plugins
GenGen's plugin system provides powerful extensibility while maintaining simplicity through configuration-based management. Whether you're using built-in plugins or developing custom ones, the system is designed to be flexible and developer-friendly.