Skip to content

Plugin documentation #2610

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
205 changes: 104 additions & 101 deletions docusaurus/docs/cms/plugins-development/create-a-plugin.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,29 +11,25 @@ tags:

# Plugin creation

There are many ways to create a Strapi 5 plugin, but the fastest and recommended way is to use the Plugin SDK.
This guide walks you through the complete process of creating, developing, and publishing Strapi 5 plugins that can be used locally or distributed via NPM and the Marketplace. The Plugin SDK is the recommended way to build plugins, providing a comprehensive toolkit from initial setup to publishing.

The Plugin SDK is a set of commands orientated around developing plugins to use them as local plugins or to publish them on NPM and/or submit them to the Marketplace.
The complete list of commands and their parameters are available in the [Plugin SDK reference](/cms/plugins-development/plugin-sdk). This page will guide you through using the main ones.

With the Plugin SDK, you do not need to set up a Strapi project before creating a plugin.
Before proceeding with plugin development, it's important to understand the difference between local and external plugins:

The present guide covers creating a plugin from scratch, linking it to an existing Strapi project, and publishing the plugin. If you already have an existing plugin, you can instead retrofit the plugin setup to utilise the Plugin SDK commands (please refer to the [Plugin SDK reference](/cms/plugins-development/plugin-sdk) for a full list of available commands).
- **Local plugins**: Plugins that are developed within your Strapi project (typically in a `plugins` folder).
- **External plugins**: Plugins that are developed outside your Strapi project (in a separate directory).

:::note
This guide assumes you want to develop a plugin external to your Strapi project. However, the steps largely remain the same if you want to develop a plugin within your existing project. If you are not [using a monorepo](#monorepo) the steps are exactly the same.
:::

:::prerequisites
<ExternalLink to="https://www.npmjs.com/package/yalc" text="yalc"/> must be installed globally (with `npm install -g yalc` or `yarn global add yalc`).
:::
The Plugin SDK can create both types of plugins. If you run the Plugin SDK command from within an existing Strapi project, it will create a local plugin. If you run it from outside a Strapi project, it will create an external plugin. The development process differs slightly between the two approaches, as outlined in the sections below.

## Getting started with the Plugin SDK
In addition to the plugin location, your Strapi project and plugin can be organized in different repository setups, which affects the development workflow:

The Plugin SDK helps you creating a plugin, linking it to an existing Strapi project, and building it for publishing.
- **Separate repositories**: Your Strapi project and plugin are in different repositories. This is common for external plugins that you plan to publish or share across multiple projects.
- **Monorepo setup**: Your Strapi project and plugin are in the same repository, often using workspace management tools like Yarn workspaces or npm workspaces. This is useful when you want to maintain everything in one place.

The full list of commands and their parameters are available in the [Plugin SDK reference](/cms/plugins-development/plugin-sdk). The present page will guide on using the main ones.
The development workflow and commands you use will vary based on both the plugin type (local vs external) and the repository setup (separate vs monorepo), as detailed in the sections below.

### Creating the plugin
## Creating the plugin

To create your plugin, ensure you are in the parent directory of where you want it to be created and run the following command:

Expand All @@ -59,167 +55,174 @@ npx @strapi/sdk-plugin init my-strapi-plugin

The path `my-strapi-plugin` can be replaced with whatever you want to call your plugin, including the path to where it should be created (e.g., `code/strapi-plugins/my-new-strapi-plugin`).

You will be ran through a series of prompts to help you setup your plugin. If you selected yes to all options the final structure will be similar to the default [plugin structure](/cms/plugins-development/plugin-structure).
You will be guided through a series of prompts to help you set up your plugin. If you select "yes" to all options, the final structure will be similar to the default [plugin structure](/cms/plugins-development/plugin-structure).

## Developing local plugins

If you run the Plugin SDK command from within an existing Strapi project, the plugin will be created in a `plugins` folder within that project. If a `plugins` folder already exists, the new plugin code will be placed there. This allows you to develop plugins locally within your project structure.

When developing your plugin locally, you also need to add the following configuration to your plugins configuration file:

```js title="/config/plugins.js|ts"
myplugin: {
enabled: true,
resolve: `./src/plugins/local-plugin`,
},
```

:::note
This setup can sometimes lead to errors such as:

### Linking the plugin to your project
```js
Error: 'X must be used within StrapiApp';
```

In order to test your plugin during its development, the recommended approach is to link it to a Strapi project.
This error often occurs when your plugin attempts to import core Strapi functionality, for example using:

Linking your plugin to a project is done with the `watch:link` command. The command will output explanations on how to link your plugin to a Strapi project.
```js
import { unstable_useContentManagerContext as useContentManagerContext } from '@strapi/strapi/admin';
```

To resolve this issue, remove `@strapi/strapi` as a dev dependency from your plugin. This ensures that your plugin uses the same instance of Strapi's core modules as the main application, preventing conflicts and the associated errors.
:::

In a new terminal window, run the following commands:
Use the `watch` command in your plugin folder to start development mode:

<Tabs groupId="yarn-npm">

<TabItem value="yarn" label="Yarn">

```bash
cd /path/to/strapi/project
yarn dlx yalc add --link my-strapi-plugin && yarn install
yarn watch
```

</TabItem>

<TabItem value="npm" label="NPM">

```bash
cd /path/to/strapi/project
npx yalc add --link my-strapi-plugin && npm install
npm run watch
```

</TabItem>

</Tabs>

:::note
In the above examples we use the name of the plugin (`my-strapi-plugin`) when linking it to the project. This is the name of the package, not the name of the folder.
:::
Then run `yarn develop` or `npm run develop` in your Strapi project to start the application with your local plugin.

Because this plugin is installed via `node_modules` you won't need to explicity add it to your `plugins` [configuration file](/cms/configurations/plugins), so running the [`develop command`](/cms/cli#strapi-develop) to start your Strapi project will automatically pick up your plugin.
## Developing external plugins

Now that your plugin is linked to a project, run `yarn develop` or `npm run develop` to start the Strapi application.
:::prerequisites
<ExternalLink to="https://www.npmjs.com/package/yalc" text="yalc"/> must be installed globally (with `npm install -g yalc` or `yarn global add yalc`).

You are now ready to develop your plugin how you see fit! If you are making server changes, you will need to restart your server for them to take effect.
**Why yalc?** `yalc` is a local package manager that enables efficient plugin development by allowing you to test your plugin in a real Strapi project without publishing it to npm first. It provides reliable linking between your plugin and Strapi project for immediate testing during development.
:::

### Building the plugin for publishing
For external plugins (plugins that don't sit within your Strapi project), you need to link them to a Strapi project for testing during development. This is done using the `watch:link` command in your plugin folder, which will output explanations on how to link your plugin to a Strapi project.

When you are ready to publish your plugin, you will need to build it. To do this, run the following command:
First, in your plugin folder, run the `watch:link` command:

<Tabs groupId="yarn-npm">

<TabItem value="yarn" label="Yarn">

```bash
yarn build && yarn verify
yarn watch:link
```

</TabItem>

<TabItem value="npm" label="NPM">

```bash
npm run build && npm run verify
npm run watch:link
```

</TabItem>

</Tabs>

The above commands will not only build the plugin, but also verify that the output is valid and ready to be published. You can then publish your plugin to NPM as you would any other package.
Then, in a new terminal window, run the following commands in your Strapi project:

## Working with the Plugin SDK in a monorepo environment {#monorepo}
<Tabs groupId="yarn-npm">

If you are working with a monorepo environment to develop your plugin, you don't need to use the `watch:link` command because the monorepo workspace setup will handle the symlink. You can use the `watch` command instead.
<TabItem value="yarn" label="Yarn">

However, if you are writing admin code, you might add an `alias` that targets the source code of your plugin to make it easier to work with within the context of the admin panel:
```bash
cd /path/to/strapi/project
yarn dlx yalc add --link my-strapi-plugin && yarn install
```

```ts
import path from 'node:path';
</TabItem>

export default (config, webpack) => {
config.resolve.alias = {
...config.resolve.alias,
'my-strapi-plugin': path.resolve(
__dirname,
// We've assumed the plugin is local.
'../plugins/my-strapi-plugin/admin/src'
),
};
<TabItem value="npm" label="NPM">

return config;
};
```bash
cd /path/to/strapi/project
npx yalc add --link my-strapi-plugin && npm install
```

:::caution
Because the server looks at the `server/src/index.ts|js` file to import your plugin code, you must use the `watch` command otherwise the code will not be transpiled and the server will not be able to find your plugin.
</TabItem>

</Tabs>

:::note
In the above examples, we use the name of the plugin (`my-strapi-plugin`) when linking it to the project. This is the name of the package, not the name of the folder.
:::

### Configuration with a local plugin
:::note
If you're working in a monorepo environment, you don't need `yalc` because the monorepo workspace setup handles the symlinking automatically.
:::

Since the Plugin SDK is primarily designed for developing plugins, not locally, the configuration needs to be adjusted manually for local plugins.
Because this plugin is installed via `node_modules`, you won't need to explicitly add it to your `plugins` configuration file as we would do for a local plugin. Running the `develop` command to start your Strapi project will automatically pick up your plugin.

When developing your plugin locally (using `@strapi/sdk-plugin`), your plugins configuration file looks like in the following example:
Now that your plugin is linked to a project, run `yarn develop` or `npm run develop` to start the Strapi application.

```js title="/config/plugins.js|ts"
myplugin: {
enabled: true,
resolve: `./src/plugins/local-plugin`,
},
```
You are now ready to develop your plugin as needed! If you are making server changes, you will need to restart your server for them to take effect.

However, this setup can sometimes lead to errors such as the following:
## Building the plugin for publishing

```js
Error: 'X must be used within StrapiApp';
```
When you are ready to publish your plugin, you will need to build it. To do this, run the following command:

This error often occurs when your plugin attempts to import core Strapi functionality, for example using:
<Tabs groupId="yarn-npm">

```js
import { unstable_useContentManagerContext as useContentManagerContext } from '@strapi/strapi/admin';
<TabItem value="yarn" label="Yarn">

```bash
yarn build && yarn verify
```

To resolve the issue, remove `@strapi/strapi` as a dev dependency from your plugin. This ensures that your plugin uses the same instance of Strapi’s core modules as the main application, preventing conflicts and the associated errors.
</TabItem>

## Setting a local plugin in a monorepo environment without the Plugin SDK
<TabItem value="npm" label="NPM">

In a monorepo, you can configure your local plugin without using the Plugin SDK by adding 2 entry point files at the root of your plugin:
```bash
npm run build && npm run verify
```

- server entry point: `strapi-server.js|ts`
- admin entry point: `strapi-admin.js|ts`
</TabItem>

### Server entry point
</Tabs>

The server entry point file initializes your plugin’s server-side functionalities. The expected structure for `strapi-server.js` (or its TypeScript variant) is:
These commands will not only build the plugin but also verify that the output is valid and ready to be published. You can then publish your plugin to NPM as you would any other package.

```js
module.exports = () => {
return {
register,
config,
controllers,
contentTypes,
routes,
};
};
```
## Admin panel development

Here, you export a function that returns your plugin's core components such as controllers, routes, and configuration. For more details, please refer to the [Server API reference](/cms/plugins-development/server-api).
If you are writing admin code, you might add an `alias` that targets the source code of your plugin to make it easier to work with within the context of the admin panel:

### Admin entry point
```ts
import path from 'node:path';

The admin entry point file sets up your plugin within the Strapi admin panel. The expected structure for `strapi-admin.js` (or its TypeScript variant) is:
export default (config, webpack) => {
config.resolve.alias = {
...config.resolve.alias,
'my-strapi-plugin': path.resolve(
__dirname,
// We've assumed the plugin is local.
'../plugins/my-strapi-plugin/admin/src'
),
};

```js
export default {
register(app) {},
bootstrap() {},
registerTrads({ locales }) {},
return config;
};
```

This object includes methods to register your plugin with the admin application, perform bootstrapping actions, and handle translations. For more details, please refer to the [Admin Panel API reference](/cms/plugins-development/admin-panel-api).

:::tip
For a complete example of how to structure your local plugin in a monorepo environment, please check out our <ExternalLink to="https://github.com/strapi/strapi/tree/develop/examples/getstarted/src/plugins/local-plugin" text="example setup in the strapi/strapi repository" />.
:::
Loading