Usage guide

Using plugins

A metalsmith plugin is just a function that is passed the Files object and the Metalsmith instance. In fact, we can even use console.log as a plugin!

metalsmith.js
const Metalsmith = require('metalsmith')

Metalsmith(__dirname)
  .use(console.log)
  .build((err, files) => {
    if (err) throw err
    console.log('Build success!')
  })
metalsmith.json
{
  "plugins": [
    {"./plugin-console-log": true}
  ]
}

*Note that for this example to work if you are using the CLI, you need to create a file plugin-console-log.js with the contents module.exports = (...args) => console.log(...args) and reference it as a local plugin in metalsmith.json

This is super-convenient when you want to quickly have a look at all the files and the metalsmith instance. You could use this little plugin to inspect how the file metadata and the metalsmith instance change in-between plugins:

metalsmith.js
const Metalsmith = require('metalsmith')
const drafts = require('@metalsmith/drafts')
const markdown = require('@metalsmith/markdown')
const layouts = require('@metalsmith/layouts')

Metalsmith(__dirname)
  .use(console.log)
  .use(drafts())
  .use(console.log)
  .use(markdown())
  .use(console.log)
  .use(layouts())
  .use(console.log)
  .build((err, files) => {
    if (err) throw err
    console.log('Build success!')
  })
metalsmith.json
{
  "plugins": [
    {"./plugin-console-log": true},
    {"@metalsmith/drafts": {}},
    {"./plugin-console-log": true},
    {"@metalsmith/markdown": {}},
    {"./plugin-console-log": true},
    {"@metalsmith/layouts": { "pattern": "**/*.html" }},
    {"./plugin-console-log": true},
  ]
}

This example also demonstrates that you can re-use the same plugin multiple times across the plugin chain, each time with different input.

Logging is cool, but what about actually manipulating the files? Say, defining additional metadata, rendering markdown files, wrapping them in a layout, adding SASS stylesheets, and optimizing everything for production. Just as the Apple iPhone’s famous 2009 commercial “There’s an app for that”, the answer to how can I do X with Metalsmith? is - there’s a plugin for that. Browse the official plugin registry for inspiration!

Plugin types

There is no official plugin type classification, but plugins can be broadly divided into a few categories:

A plugin could fit into multiple categories:

Plugins that start with the @metalsmith/ prefix are core plugins. They are officially supported by Metalsmith and there’s a good chance that you will need most of them when building a static site. Here are some of the most common ones:

Plugin order

Plugin order is very important in Metalsmith. As a rule of thumb, .use(common sense): you only want to minify HTML after the markdown file has been processed with @metalsmith/markdown and then wrapped in @metalsmith/layouts. Generally, you want plugins that inject new files or add metadata to be run at the start of the plugin chain so it is available in layouts and for other plugins to process. @metalsmith/drafts is efficient as the first plugin because in a production build it immediately removes the files you don’t want to process anyway.

Conditionally running plugins

If you’re using the Metalsmith CLI, there’s only one way to run plugins conditionally: create multiple metalsmith.json configs. The common use case is having a development config and a production config. For example, we would like to remove draft files and minify the HTML only in production:

metalsmith.dev.json
{
  "plugins": [
    { "@metalsmith/markdown": { } },
    { "@metalsmith/layouts": { } }
  ]
}
metalsmith.json
{
  "plugins": [
    { "@metalsmith/markdown": { } },
    { "@metalsmith/drafts": { } },
    { "@metalsmith/layouts": { } },
    { "metalsmith-html-minifier": { } }
  ]
}

And run it with:

metalsmith --config metalsmith.dev.json
metalsmith --config metalsmith.json

If you have more than 2-3 conditions we recommend using the JS API. You can run a plugin conditionally by assigning the metalsmith build to a variable, and using native javascript if statements. The same example from above using the JS API:

metalsmith.js
const Metalsmith = require('metalsmith');
const minifyHTML = require('metalsmith-html-minifier');
const isProduction = process.env.NODE_ENV !== 'development';

const metalsmith = Metalsmith(__dirname);
if (isProduction) {
  metalsmith.use(minifyHTML());
}
metalsmith.build(err => {
  if (err) throw err
  console.log('Build success!')
})

If you need to check multiple conditions at different places in the build, the metalsmith-if plugin might be a better match:

metalsmith.js
const when = require('metalsmith-if');
const minifyHTML = require('metalsmith-html-minifier');
const production = process.env.NODE_ENV !== 'development';

Metalsmith(__dirname)
  .use(when(production, minifyHTML())
  .build(err => {
    if (err) throw err
    console.log('Build success!')
  })

Defining metadata

You can define global metadata for a Metalsmith build using the metalsmith.metadata method:

metalsmith.js
const Metalsmith = require('metalsmith')

Metalsmith(__dirname)
  .metadata({
    sitename: 'My Static Site & Blog',
    description: 'It\'s about saying »Hello« to the World.',
    generator: 'Metalsmith',
    url: 'https://metalsmith.io/'
  })
metalsmith.json
{
  "metadata": {
    "sitename": "My Static Site & Blog",
    "description": "It's about saying »Hello« to the World.",
    "generator": "Metalsmith",
    "url": "https://metalsmith.io/"
  }
}

Global metadata can be dynamically added from files in metalsmith.directory or metalsmith.source with a plugin like @metalsmith/metadata, which can help keep your main build file clean. Here is the same metadata in a separate yaml file:

src/site.yaml
sitename: My Static Site & Blog
description: It's about saying »Hello« to the World.
generator: Metalsmith
url: 'https://metalsmith.io/'

…that we can then refer to in the build like:

metalsmith.js
const Metalsmith = require('metalsmith')
const metadata = require('@metalsmith/metadata')

Metalsmith(__dirname)
  .use(metadata({
    site: 'src/site.yaml'
  }))
metalsmith.json
{
  "plugins": [
    { "@metalsmith/metadata": { "site": "src/site.yaml" } }
  ]
}

File metadata can be defined as front-matter in any file (provided that you didn’t disable it with metalsmith.frontmatter(false)):

---
title: My first post went a little like this
description: A turn, an ending, and a twist
---
No more drafts and no more waiting

File metadata can be added dynamicaly with plugins like @metalsmith/default-values or metalsmith-filemetadata. Below is an example using @metalsmith/default-values to automatically assign the post.hbs layout to files by folder and mark all files in the drafts folder as draft:

metalsmith.js
const Metalsmith = require('metalsmith')
const defaultValues = require('@metalsmith/default-values')
const drafts = require('@metalsmith/drafts')
const markdown = require('@metalsmith/markdown')
const layouts = require('@metalsmith/layouts')

Metalsmith(__dirname)
  .use(defaultValues([
    {
      pattern: 'posts/**/*.md',
      defaults: {
        layout: 'post.hbs'
      }
    },
    {
      pattern: 'drafts/**',
      defaults: { draft: true }
    }
  ]))
  .use(process.env.NODE_ENV === 'production' ? drafts() : () => {})
  .use(markdown())
  .use(layouts())
  .build((err, files) => {
    if (err) throw err
    console.log('Build success')
  })
metalsmith.dev.json
{
  "plugins": [
    {
      "@metalsmith/default-values": [
        { "pattern": "posts/**/*.md", defaults: { "layout": "post.hbs" }},
        { "pattern": "drafts/**", defaults: { "draft": true }},
      ] 
    },
    { "@metalsmith/drafts": {} },
    { "@metalsmith/markdown": {} },
    { "@metalsmith/layouts": {} }
  ]
}
× This website may use local storage for purely functional purposes (for example to remember preferences), and anonymous cookies to gather information about how visitors use the site. By continuing to browse this site, you agree to its use of cookies and local storage.