# Create a Plugin In this document, you’ll learn how to create a plugin and publish it. If you’re interested to learn more about what plugins are and where to find available official and community plugins, check out the [overview document](overview.md). ## Prerequisites This guide uses the Medusa CLI throughout different steps. If you don’t have the Medusa CLI installed you can install it with the following command: ```bash npm2yarn npm install @medusajs/medusa-cli -g ``` :::note If you run into any errors while installing the CLI tool, check out the [troubleshooting guide](../../../troubleshooting/cli-installation-errors.mdx). ::: --- ## Initialize Project The recommended way to create a plugin is using the Medusa CLI. Run the following command to create a new Medusa project: ```bash medusa new medusa-plugin-custom ``` Where `medusa-plugin-custom` is the name of the plugin you’re creating. In Medusa, plugins are named based on their functionalities. By convention, all plugin names start with `medusa` followed by a descriptive name of what the plugin does. For example, the Stripe plugin is named `medusa-payment-stripe`. --- ## Changes to package.json ### Rename Project Name Update the `name` field in the `package.json` file to the name of your plugin. This should be the same name that you chose when running the `medusa new` command. ### Change Dependencies A basic Medusa server installed with the `medusa new` command has dependencies similar to this: ```json title=package.json "dependencies": { "@medusajs/medusa": "^1.3.1", "@medusajs/medusa-cli": "^1.3.0", "medusa-fulfillment-manual": "^1.1.31", "medusa-interfaces": "^1.3.0", "medusa-payment-manual": "^1.0.16", "medusa-payment-stripe": "^1.1.38", "typeorm": "^0.2.36" }, "devDependencies": { "@babel/cli": "^7.14.3", "@babel/core": "^7.14.3", "@babel/preset-typescript": "^7.14.5", "babel-preset-medusa-package": "^1.1.19" } ``` For a plugin, a lot of these dependencies are not necessary or should be labeled as [peer dependencies](https://docs.npmjs.com/cli/v8/configuring-npm/package-json#peerdependencies). Therefore, it’s important to make changes to the dependencies of your plugin. The recommended change is the following: ```json title=package.json "peerDependencies": { "@medusajs/medusa": "^1.3.1", "medusa-interfaces": "^1.3.0", "typeorm": "^0.2.36" }, "devDependencies": { "@babel/cli": "^7.14.3", "@babel/core": "^7.14.3", "@babel/preset-typescript": "^7.14.5", "babel-preset-medusa-package": "^1.1.19", } ``` The packages `@medusajs/medusa` and `medusa-interfaces` act as peer dependencies. They’ll be installed while you develop your package, and they are required when your plugin is installed in another NPM project. You remove the packages `medusa-fulfillment-manual`, `medusa-payment-manual`, and `medusa-payment-stripe` as they are fulfillment and payment plugins necessary for a Medusa server, but not for a plugin. Additionally, you remove `@medusajs/medusa-cli` as you don’t need to use the Medusa CLI while developing a plugin. Once you’re done making these changes, re-run the install command to update your `node_modules` directory: ```bash npm2yarn npm install ``` This section includes recommended changes to your `package.json`. You can skip any of these changes if you don’t find them necessary to your plugin. ### Recommended: Change scripts :::caution If you don't make changes to the `build` and `watch` commands, please be aware of the [expected plugin structure](#plugin-structure). ::: A basic Medusa installation comes with the following scripts: ```json title=package.json "scripts": { "seed": "medusa seed -f ./data/seed.json", "build": "babel src --out-dir . --ignore **/__tests__ --extensions \".ts,.js\"", "start": "medusa develop" } ``` The `seed` and `start` scripts aren't necessary for plugin development so you can remove them. It’s also recommended to add the `watch` script that automatically compiles your files if they are changed: ```json title=package.json "watch": "babel -w src --out-dir . --ignore **/__tests__ --extensions \".ts,.js\"" ``` This is helpful when testing the plugin. :::note Testing the plugin is covered in a [later section](#test-your-plugin). ::: Another recommended script is the `prepare` script that builds your files under a “production” environment: ```json title=package.json "prepare": "cross-env NODE_ENV=production npm run build" ``` You would typically run this script before publishing your plugin. This script requires installing the package `cross-env` as a development dependency: ```bash npm2yarn npm install --save-dev cross-env ``` ### Recommended: Change Basic Info `package.json` holds information that further describes the package or the author that created the package. It is recommended to make the following changes: - `description`: Change this to a sentence that describes what your plugin does. - `author`: Your name and email. - `repository`: The repository that holds your plugin’s codebase. - `keywords`: This should hold the keywords that are related to your plugin. It’s recommended that all plugins use the keywords `medusa-plugin` or `medusa`. --- ## Develop your Plugin Now, You can start developing your plugin. This can include adding services, endpoints, entities, or anything that's relevant to your plugin. ### Plugin Structure While developing your plugin, you can create your TypeScript or JavaScript files under the `src` directory. This includes creating services, endpoints, migrations, etc... However, before you test the changes on a Medusa server or publish your plugin, you must transpile your files, which moves them into the root of your plugin directory. For example, if you have an endpoint in `src/api/index.js`, after running the `build` or `watch` commands [as defined earlier](#change-scripts), the file should be transpiled into `api/index.js` in your plugin's root. If files and directories aren't placed in the root of your plugin, the Medusa server won't detect or load them. An example of a plugin's directory before testing or publishing: ```bash noReport medusa-plugin-custom | |_ _ _ api | | | |_ _ _ index.js | |_ _ _ migrations | | | |_ _ _ _UserChanged.js | |_ _ _ src | | | |_ _ _ api | | | | | |_ _ _ index.ts | | | |_ _ _ migrations | | | |_ _ _ _UserChanged.ts | |_ _ _ package.json //... other files ``` ### Development Resources This guide doesn't cover how to create different files and components. If you’re interested in learning how to do that, you can check out these guides: - How to [create endpoints](../endpoints/add.md) - How to [create a service](../services/create-service.md) - How to [create a subscriber](../subscribers/create-subscriber.md) - How to [create an entity](./../entities/index.md) - How to [create a migration](../migrations/index.md) --- ## Add Plugin Configuration Plugins often allow developers that will later use them to enter their own configuration. For example, you can allow developers to specify the API key of a service you’re integrating. To pass a plugin its configurations on a Medusa server, you have to add it to the `plugins` array in `medusa-config.js`: ```jsx title=medusa-config.js const plugins = [ // ... { resolve: `medusa-plugin-custom`, options: { name: "My Store", }, }, ] ``` Then, you can have access to your plugin configuration in the constructor of services in your plugin: ```jsx title=src/service/test.ts // In a service in your plugin class MyService extends TransactionBaseService { constructor(container, options) { super(container) // options contains plugin configurations this.name = options.name } // ... } ``` You can also have access to the configurations in endpoints in your plugin: ```jsx title=src/api/index.ts // in an endpoint in your plugin export default (rootDirectory, options) => { // options contain the plugin configurations const router = Router() router.get("/hello-world", (req, res) => { res.json({ message: `Welcome to ${options.name ? options.name : "Medusa"}!`, }) }) return router } ``` :::tip Make sure to include in the README of your plugin the configurations that can be passed to a plugin. ::: --- ## Test Your Plugin While you develop your plugin, you’ll need to test it on an actual Medusa server. This can be done by using the [npm link](https://docs.npmjs.com/cli/v8/commands/npm-link) command. In the root of your plugin directory, run the following command: ```bash npm2yarn npm link ``` Then, change to the directory of the Medusa server you want to test the plugin on and run the following command: ```bash npm2yarn npm link medusa-plugin-custom ``` Where `medusa-plugin-custom` is the package name of your plugin. After linking to your plugin in a local Medusa server, either run the `build` or `watch` commands in your plugin directory: ```bash npm2yarn # in the directory of the plugin npm run watch ``` :::tip If you’re running the `watch` command, you don’t need to run the `build` command every time you make a change to your plugin. ::: Then, add your plugin into the array of plugins in `medusa-config.js`: ```jsx title=medusa-config.js const plugins = [ // ... { resolve: `medusa-plugin-custom`, // if your plugin has configurations options: { name: "My Store", }, }, ] ``` :::note If your plugin has migrations, you must run them before you start the server. Check out the [Migrations guide](../migrations/overview.md#migrate-command) for more details. ::: Finally, start your server and test your plugin’s functionalities: ```bash npm2yarn npm run start ``` ### Troubleshoot Errors #### Error: The class must be a valid service implementation Please make sure that your plugin is following the correct structure. If the error persists then please try the following fix: ```bash npm2yarn cd /node_modules/medusa-interfaces npm link cd /node_modules/@medusajs/medusa npm link cd rm -rf node_modules/medusa-interfaces rm -rf node_modules/@medusajs/medusa npm link medusa-interfaces npm link @medusajs/medusa npm link cd npm link your-plugin ``` Where `` is the path to your Medusa server and `` is the path to your plugin. This links the `medusa-interfaces` and `@medusajs/medusa` packages from your `medusa-backend` to your plugin directory and then links your plugin to your `medusa-backend`. #### APIs not loading If the APIs you added to your Medussa server are not loading then please try the following steps: ```bash npm2yarn cd rm -rf node_modules cd /node_modules/ npm install cd npm run build cd npm run start ``` Where `` is the path to your Medusa server, `` is the path to your plugin and `` is the name of your plugin as it is in your plugin `package.json` file. :::note It is safe to ignore any `cross-env: command not found` error you may receive. ::: --- ## NPM Ignore File Not all files that you use while developing your plugin are necessary to be published. For example, the files you add in the `src` directory are compiled to the root of the plugin directory before publishing. Then, when a developer installs your plugin, they’ll just be using the files in the root. So, you can ignore files and directories like `src` from the final published NPM package. To do that, create the file `.npmignore` with the following content: ```bash title=.npmignore /lib node_modules .DS_store .env* /*.js !index.js yarn.lock src .gitignore .eslintrc .babelrc .prettierrc #These are files that are included in a #Medusa project and can be removed from a #plugin project medusa-config.js Dockerfile medusa-db.sql develop.sh ``` --- ## Publish Plugin Once you’re done developing your plugin you can publish the package on NPM’s registry so that other developers can benefit from it and use it. Before you publish a plugin, you must [create an account on NPM](https://www.npmjs.com/signup). ### Prepare Plugin Before you publish or update your plugin, make sure to run the `prepare` command [defined earlier](#recommended-change-scripts): ```bash npm2yarn npm run prepare ``` ### Login In your terminal, log in with your NPM account: ```bash npm login ``` You’ll be asked to enter your NPM email and password. ### Publish Plugin Package Once you’re logged in, you can publish your package with the following command: ```bash npm publish ``` Your package is then published on NPM and everyone can use it and install it. ### Update Plugin To update your plugin at a later point, you can run the following command to change the NPM version: ```bash npm version ``` Where `` indicates the type of version update you’re publishing. For example, it can be `major` or `minor`. You can see the [full list of types in NPM’s documentation](https://docs.npmjs.com/cli/v8/commands/npm-version). Then, publish the new update: ```bash npm publish ``` --- ## Add Plugin to Medusa’s Repository All officially-supported plugins are available in the [`packages` directory of the Medusa GitHub repository](https://github.com/medusajs/medusa/tree/master/packages). If you’re interested in adding your plugin, you need to create a new pull request (PR) where you add your plugin inside the `packages` directory. Our team will then review your plugin, and if it’s approved the PR will be merged and your plugin will be available on Medusa’s repository. :::note Before contributing to the Medusa repository, please check out the [contribution guidelines](https://github.com/medusajs/medusa/blob/master/CONTRIBUTING.md). ::: --- ## Install a Plugin To install any published plugin, you can run the following command on any Medusa server project: ```bash npm2yarn npm install medusa-plugin-custom ``` --- ## See Also - [Available official plugins](https://github.com/medusajs/medusa/tree/master/packages) - [Services reference](references/services/../../../../../references/services/classes/AuthService.md) - [Events reference](../subscribers/events-list.md)