---
title: Plugin guide
---

Plugins allow you to extend FreeSewing with new features and functionality.
A FreeSewing plugin can extend FreeSewing in 3 different ways:

- It can [provide macros](#macro-methods), which are a way to automate a number of steps into a
  single command.
- It can [hook into the pattern](#lifecycle-hook-methods), which allows you to manipulate the pattern or
  interact with it at various stages of it's lifecycle.
- It can [provide store methods](#store-methods), which allows you to add new ways to handle data
  in the pattern, including providing a custom logger.

We have [a list of plugins](/reference/plugins/) that we maintain, but
if you can't find what you're looking for, you can write your own plugin.

If you plan on doing that or if you would like to understand how plugins work,
this guide is for you.

## Plugin structure

A FreeSewing plugin is a plain object with the following structure:

```mjs
Object plugin = {
  String name,
  String version,
  Object hooks,
  Object macros,
  Array store,
}
```

A plugin **must** have the `name` and `version` properties.
The other properties are optional, and they map to the three different functionalities macros can provide:

- [`hooks`](#lifecycle-hook-methods): Holds an object with lifecycle hooks the plugin wants to hook into
- [`macros`](#macro-methods): Holds and object with macros the plugin provides
- [`store`](#store-methods): Holds and Array with store methods the plugin provides.

Click on the links above for more details on the structure of these properties.

## Lifecycle hook methods

FreeSewing plugins can provide hooks, which is a way to hook into the pattern's
lifecycle.

### Signature

To provide one or more hooks, your plugin should have a `hooks` property that
is an object where the keys are the lifecycle hook name and the value holds a
method. When the lifecycle hook is triggered, your method will be called.

```mjs
const myPlugin = {
  name: 'example',
  version: '0.0.1',
  hooks: {
    hookName: function (obj, data = {}) {
    }
  }
}
```

If you want to attach multiple methods to the same lifecycle hook, you can pass
them as an array:

```mjs
const myPlugin = {
  name: 'example',
  version: '0.0.1',
  hooks: {
    hookName: [
      function one (obj, data = {}) { },
      function two (obj, data = {}) { }
    ]
  }
}
```

### Arguments

All lifecycle methods will receive two parameters:

- An object relevant to the lifecycle hook. See the [hooks API reference](/reference/hooks/) for details.
- Data passed when the hook was registered (optional)

### Notes

Refer to the [hooks API reference](/reference/hooks/) for a list of all
available lifecycle hooks.

## Macro methods

FreeSewing plugins can provide macros, which is a way to automate multiple
steps into a single command.

### Signature

To provide one or more macros, your plugin should have a `macros` property that
is an object where the keys are the macro name, and the value holds a method to
run when the macro is executed.

```mjs
const myPlugin = {
  name: 'example',
  version: '0.0.1',
  macros: {
    example: function(so, { log }) {
      log.info('Running the example macro')
    }
  }
}
```

### Arguments

All macros receive two arguments:

- `so`: A plain object holding configuration object passed to the macro
- `props`: The same object as passed to the [`Part.draft()`](/reference/api/part/draft) method that you can destructure

:::note Macros take only 1 argument

When writing a macro, keep in mind that all information that needs to be passed
to a macro needs to be contained in a single argument.

Typically, you use a single plain object to configure the macro.

:::

### Return value

Macros do not need to return anything. If they do, it will be ignored.

## Store methods

FreeSewing plugins can provide store methods, which facilitate data handling
within a pattern.

### Signature

To provide one or more store methods, your plugin should have a `store` property that
is an array where each member is itself an array with two members:

- The first member holds the key to attach the method to (in dot notation)
- The second member holds the method to attach

```mjs
const myPlugin = {
  name: 'example',
  version: '0.0.1',
  store: [
    [
      'log.panic',
      function(store, ...params) {
        store.setIfUnset('logs.panic', new Array())
        store.push(...params)
      }
    ]
  }
}
```

### Arguments

All store methods receive at least two arguments:

- `store`: The store object itself
- `...params`: All additional plugins that were passed to the store method

### Overwriting store methods

You are allowed to overwrite existing store methods.
As it happens, this is how you should implement a custom logging solution,
by overwriting the logging methods under the store's `log` key,

However, the following store methods cannot be overwritten:

- `extend()`
- `get()`
- `push()`
- `set()`
- `setIfUnset()`
- `unset()`

### Return value

Store methods do not need to return anything. If they do, it will be ignored.

## Loading plugins

Plugins can be loaded at build time and added to the design.
Or, they can be added at run time and added to an instantiated pattern.

To load a plugin at build time, it should be added to [the `plugins` key of the part configuration](/reference/api/part/config/plugins).

To load a plugin at run time, it should be loaded with a call to [`Pattern.use()`](/reference/api/pattern/use).

Please refer to the relevant documentation for more details.
