Skip to content

Writing pluglets


New, as of version 0.4.20.



A pluglet is a preinstalled module for mkdocs-macros, which is installed thanks to Pythons standard packaging process.

The only thing needed (as a bare minimum), is to implement a single function, define_env():

def define_env(env):

What makes a pluglet different from a plain module?

The only difference between a pluglet and an ordinary mkdocs-macros module (typically or main directory), is that the pluglet is preinstalled. In this way, you can benefit from pluglets written by others, and you could share the pluglets that you wrote.

A pluglet can do two things that any mkdocs-macro module can do:

  1. Define macros.
  2. Perform changes on the architecture of the website.

What makes a pluglet different from a plugin?

A pluglet is distinct from an MkDocs plugin. A pluglet is a more lightweight tool that sits over the mkdocs-macros plugin and uses the framework provided by it.

There is no need to implement a subclass of the BasePlugin class, only to declare a define_env(env) function.

Could a pluglet do everything a plugin can do?

The answer is, quite a lot, but not everything. MkDocs plugins are able to rely on a wide range of events, which are hooks for acting on the website at various stages of the config/build process.

A mkdocs-macros pluglet operates mostly on the on_config event of MkDocs thanks to define_env(env)hook; but its use can be extended thanks to other hooks.

Using existing pluglets

Declaring a pluglet for an MkDocs project

For your specific documentation project, you may call already installed pluglets (which would appear with pip list):

pip list | grep mkdocs-macros

Use the modules argument.
It is a list, so that you can declare one or more:

e.g. :

  - macros:
      modules: [mkdocs_macros_test]


  - macros:
      modules: [mkdocs_macros_foo, mkdocs_macros_bar]

Auto-installable pluglets

Every pluglet specified in the moduleslist should be available.

However, if the pluglet cannot be found, mkdocs will attempt to install it (with pip3 install) from the standard repositories (Pypi and others defined locally). If not, mkdocs will fail and exit.

Make installations easier!

The purpose of this feature is to facilitate the management of environments with several mkdocs websites, typically when a pluglet is designed for a whole company, project, etc.

In this way, the macros and filters declared in the pluglet will work out of the box, as long as the pluglet is properly defined in the config file (and the pluglet is auto-installable).

In some cases, the name of the source package i:

  - macros:
      modules: [mkdocs-macros-test:mkdocs_macros_test]

In the example above mkdocs-macros-test is the package source, and mkdocs_macros_test is the package name for the import statement.

If those names are correct everything should fall into place when you type the mkdocs serve or mkdocs build commands.

Implementing a new pluglet

General Principles

You can develop pluglets for mkdocs-macros-plugin and publish them on github and pypi.

How to name a pluglet

The names for pluglets are not constrained. As a naming convention, we strongly recommend:

  • a package name starting with mkdocs-macros-
  • an import name starting mkdocs_macros_, i.e. replacing the hyphen (-) symbol by underscore (_).

Typical structure of a pluglet


You will find a simple example with the mkdocs-test pluglet, available on gihub.

The file will typically have this form:

from setuptools import setup

    description="Foo library for macros plugin",
    license='<YOUR CHOICE>',
    author='Joe Bloe'

The structure will be typically like so:


or like so (if it is more complex):

├── mkdocs_macros_test
│   └──
|   └──


The subdirectory containing the code will have to be called mkdocs_macros_foo (underscores).

How to write the code

For the code itself, proceed as for a usual module:

Code of the pluglet

def test_fn(x:float):
    "Test function"
    return x * 4 / 3

def say_hello(s:str):
    "Test procedure"
    return "<i>Hello %s</i>" % s

def define_env(env):
    "Declare environment for jinja2 templates for markdown"

    for fn in [test_fn, say_hello]:

    # you could, of course, also define a macro here:
    def test_fn2(s:str):
        return "I am displaying this: %s" % s