When I first encountered Metalsmith, I thought that it was similar to Jekyll. It wasn't until I had worked on two to three projects using Metalsmith that I fully realized its flexibility and power. This post is an introduction to Metalsmith and its extensibility.

What is Metalsmith?

We keep referring to Metalsmith as a “static site generator”, but it’s a lot more than that. Since everything is a plugin, the core library is actually just an abstraction for manipulating a directory of files.

If Rails is an opinionated approach to designing and building web applications, Jekyll is the same for building blogs and Middleman is the same for building static sites. Conversely, Express / Koa are unopinionated in their approaches, as is Metalsmith to static sites.

The term 'opinionated' suggests how many software design decisions have already been decided for you.

Metalsmith, at its core, takes files in a source directory, perform operations on them via plugins, and writes those files into a destination directory. Plugins can do virtually anything: create new files, filter out files, modify files based on some logic, etc (note this means that plugin order does matter; transformations done by one plugin can be seen and used by following plugins, making the process a modular build pipeline). The entire ecosystem of plugins is what makes Metalsmith so flexible.

Note that you have control over telling Metalsmith the location of the source and destination directories.

How does Metalsmith (and its plugins) work?

For example, let's see what Metalsmith does if there are no plugins. Here is the directory (`./node_modules` is hidden):

.
├── src
| ├── index.md
| └── nested
| └── index.md
└── index.js

Here is `index.js` that we'll be running (you can also run Metalsmith via CLI, more on that later):

..nothing has changed (not even the text inside the markdown files). This is expected since no plugins (i.e. transforms) are being performed.

Let's dig one level deeper and see what Metalsmith is seeing to help us build a better picture of what's going on. We'll add this really simple function (hint: it's a plugin!) that just logs some info:

Yes, there is a ton of junk in `files`! Just note that the property `contents` in each file is the only important thing, you can ignore everything else.

We see that the argument `files` in our function is an object map of all the files in the source directory (and that `files[PATH].contents` is the body of the file). Many plugins will iterate through `files` and perform operations on them.

Also, we see that the second argument, `metalsmith`, contains some metadata: plugins, directory, even an explicit object for metadata, etc. This is important, because plugins can store config or other information in metadata, or access the metadata to help with file operations.

The last argument, `done`, is a function that you can call to tell Metalsmith to go to the next plugin in its queue (or `.build()`, if it's the last one).

Front-matter Makes it Easy

Front-matter is YAML that can precede any file (sandwiched by two `---`). Metalsmith will automatically convert this to a key-value in the `file`'s object. For example, the below in `./src/index.md`:

We now have `title`, `draft`, and `foo` available for our plugins to use. Many plugins rely on the front-matter to easily transform files, such as filtering out files with `draft: true` or organizing files into different collections (e.g. `collection: articles`).

Here are some example plugins that you can check out to see how they're manipulating the `files` and `metalsmith` arguments.

collections: group files by category (this is a neat plugin that will find all files in the same category and connect them; it'll add the second file as a property `next` of the first file, etc.)

markdown: turn markdown into HTML by replacing the `file.contents` with HTML (using marked)

a custom plugin that saves the `contents` to `body` so it can be used in the atom feed (later, `contents` is going to be merged with the layouts plugin)

a custom plugin that attaches author metadata to each file (uses an internal web service that returns team members at Segment)

a custom plugin that attaches category metadata to each post

a custom plugin that attaches related posts to each post; it adds a `related` property whose value is an array of other posts to each post

permalinks: add `path` object to each `file` that will serve as the URL

only-build: delete any reference from the `files` hash that is not specified to be built (for performance)

templates: pass each file in the `files` hash through the template denoted `file.template`, so that the written output in the destination file is the final HTML (templates is deprecated and split into two smaller plugins—metalsmith-layouts and metalsmith-in-place)

Still with me? Thats a lot to take in. And on top of that, some of the above plugins require specific things to include in front-matter or in variables set in the environment to work properly.

Aside from blog generators (of which you could make tons of different ones with different plugins), here are some other ideas for which you can use Metalsmith: