docs: docs for next release (#13621)

* docs: docs for next release

* changes to opentelemetry dependencies

* document plugin env variables

* document admin changes

* fix vale error

* add version notes

* document campaign budget updates

* document campaign changes in user guide

* document chages in cluster mode cli

* documented once promotion allocation

* document multiple API keys support
This commit is contained in:
Shahed Nasser
2025-10-21 10:32:08 +03:00
committed by GitHub
parent f38f0f9aca
commit ed715813a5
54 changed files with 1621 additions and 252 deletions
+21
View File
@@ -0,0 +1,21 @@
import { ChildDocs } from "docs-ui"
export const metadata = {
title: `${pageNumber} Medusa Codemods`,
}
# {metadata.title}
In this chapter, you'll learn about Medusa codemods and the list of available codemods.
## What are Codemods?
Codemods are scripts that help you automate codebase changes. They are especially useful when updating to a new version that requires large changes to your codebase.
Medusa provides codemods to help you update your codebase. Use these codemods when updating to their respective versions.
---
## List of Medusa Codemods
<ChildDocs type="item" />
@@ -0,0 +1,279 @@
export const metadata = {
title: `${pageNumber} Replace Imports Codemod (v2.11.0+)`,
}
# {metadata.title}
In this chapter, you'll learn about the codemod that helps you replace imports in your codebase when upgrading to Medusa v2.11.0.
## What is the Replace Imports Codemod?
[Medusa v2.11.0](https://github.com/medusajs/medusa/releases/tag/v2.11.0) optimized the package structure by consolidating several external packages into the `@medusajs/framework` package.
Previously, you had to install and manage packages related to MikroORM, Awilix, OpenTelemetry, and the `pg` package separately in your Medusa application. Starting with v2.11.0, these packages are included in the `@medusajs/framework` package.
For example, instead of importing `@mikro-orm/core`, you now import it from `@medusajs/framework/mikro-orm/core`. This applies to all of the following packages:
- `@mikro-orm/*` packages (for example, `@mikro-orm/core`, `@mikro-orm/migrations`, etc.) -> `@medusajs/framework/mikro-orm/{subpath}`
- `awilix` -> `@medusajs/framework/awilix`
- `pg` -> `@medusajs/framework/pg`
- `@opentelemetry/instrumentation-pg` -> `@medusajs/framework/opentelemetry/instrumentation-pg`
- `@opentelemetry/resources` -> `@medusajs/framework/opentelemetry/resources`
- `@opentelemetry/sdk-node` -> `@medusajs/framework/opentelemetry/sdk-node`
- `@opentelemetry/sdk-trace-node` -> `@medusajs/framework/opentelemetry/sdk-trace-node`
To help you update your codebase to reflect these changes, Medusa provides a codemod that automatically replaces imports of these packages throughout your codebase.
---
## Using the Replace Imports Codemod
To use the replace imports codemod, create the file `replace-imports.js` in the root of your Medusa application with the following content:
```js
#!/usr/bin/env node
const fs = require("fs")
const path = require("path")
const { execSync } = require("child_process")
/**
* Script to replace imports and require statements from mikro-orm/{subpath}, awilix, and pg
* to their @medusajs/framework equivalents
*/
// Define the replacement mappings
const replacements = [
// MikroORM imports - replace mikro-orm/{subpath} with @medusajs/framework/mikro-orm/{subpath}
{
pattern: /from\s+['"]@?mikro-orm\/([^'"]+)['"]/g,
// eslint-disable-next-line quotes
replacement: 'from "@medusajs/framework/mikro-orm/$1"',
},
// Awilix imports - replace awilix with @medusajs/framework/awilix
{
pattern: /from\s+['"]awilix['"]/g,
// eslint-disable-next-line quotes
replacement: 'from "@medusajs/framework/awilix"',
},
// PG imports - replace pg with @medusajs/framework/pg
{
pattern: /from\s+['"]pg['"]/g,
// eslint-disable-next-line quotes
replacement: 'from "@medusajs/framework/pg"',
},
// OpenTelemetry imports - replace @opentelemetry/instrumentation-pg, @opentelemetry/resources,
// @opentelemetry/sdk-node, and @opentelemetry/sdk-trace-node with @medusajs/framework/opentelemetry/{subpath}
{
pattern: /from\s+['"]@?opentelemetry\/(instrumentation-pg|resources|sdk-node|sdk-trace-node)['"]/g,
// eslint-disable-next-line quotes
replacement: 'from "@medusajs/framework/opentelemetry/$1"',
},
// MikroORM require statements - replace require('@?mikro-orm/{subpath}') with require('@medusajs/framework/mikro-orm/{subpath}')
{
pattern: /require\s*\(\s*['"]@?mikro-orm\/([^'"]+)['"]\s*\)/g,
// eslint-disable-next-line quotes
replacement: 'require("@medusajs/framework/mikro-orm/$1")',
},
// Awilix require statements - replace require('awilix') with require('@medusajs/framework/awilix')
{
pattern: /require\s*\(\s*['"]awilix['"]\s*\)/g,
// eslint-disable-next-line quotes
replacement: 'require("@medusajs/framework/awilix")',
},
// PG require statements - replace require('pg') with require('@medusajs/framework/pg')
{
pattern: /require\s*\(\s*['"]pg['"]\s*\)/g,
// eslint-disable-next-line quotes
replacement: 'require("@medusajs/framework/pg")',
},
// OpenTelemetry require statements - replace require('@opentelemetry/instrumentation-pg'),
// require('@opentelemetry/resources'), require('@opentelemetry/sdk-node'), and
// require('@opentelemetry/sdk-trace-node') with require('@medusajs/framework/opentelemetry/{subpath}')
{
pattern: /require\s*\(\s*['"]@?opentelemetry\/(instrumentation-pg|resources|sdk-node|sdk-trace-node)['"]\s*\)/g,
// eslint-disable-next-line quotes
replacement: 'require("@medusajs/framework/opentelemetry/$1")',
},
]
function processFile(filePath) {
try {
const content = fs.readFileSync(filePath, "utf8")
let modifiedContent = content
let wasModified = false
replacements.forEach(({ pattern, replacement }) => {
const newContent = modifiedContent.replace(pattern, replacement)
if (newContent !== modifiedContent) {
wasModified = true
modifiedContent = newContent
}
})
if (wasModified) {
fs.writeFileSync(filePath, modifiedContent)
console.log(`✓ Updated: ${filePath}`)
return true
}
return false
} catch (error) {
console.error(`✗ Error processing ${filePath}:`, error.message)
return false
}
}
function getTargetFiles() {
try {
// Get the current script's filename to exclude it from processing
const currentScript = path.basename(__filename)
// Find TypeScript/JavaScript files, excluding common directories that typically don't contain target imports
const findCommand = `find . -name node_modules -prune -o -name .git -prune -o -name dist -prune -o -name build -prune -o -name coverage -prune -o -name "*.ts" -print -o -name "*.js" -print -o -name "*.tsx" -print -o -name "*.jsx" -print`
const files = execSync(findCommand, {
encoding: "utf8",
maxBuffer: 50 * 1024 * 1024, // 50MB buffer
})
.split("\n")
.filter((line) => line.trim())
console.log(files)
const targetFiles = []
let processedCount = 0
console.log(`📄 Scanning ${files.length} files for target imports and require statements...`)
for (const file of files) {
try {
// Skip the current script file
const fileName = path.basename(file)
if (fileName === currentScript) {
processedCount++
continue
}
const content = fs.readFileSync(file, "utf8")
if (
/from\s+['"]@?mikro-orm\//.test(content) ||
/from\s+['"]awilix['"]/.test(content) ||
/from\s+['"]pg['"]/.test(content) ||
/require\s*\(\s*['"]@?mikro-orm\//.test(content) ||
/require\s*\(\s*['"]awilix['"]/.test(content) ||
/require\s*\(\s*['"]pg['"]/.test(content)
) {
targetFiles.push(file.startsWith("./") ? file.slice(2) : file)
}
processedCount++
if (processedCount % 100 === 0) {
process.stdout.write(
`\r📄 Processed ${processedCount}/${files.length} files...`
)
}
} catch (fileError) {
// Skip files that can't be read
continue
}
}
if (processedCount > 0) {
console.log(`\r📄 Processed ${processedCount} files. `)
}
return targetFiles
} catch (error) {
console.error("Error finding target files:", error.message)
return []
}
}
function main() {
console.log("🔄 Finding files with target imports and require statements...")
const targetFiles = getTargetFiles()
if (targetFiles.length === 0) {
console.log("️ No files found with target imports or require statements.")
return
}
console.log(`📁 Found ${targetFiles.length} files to process`)
let modifiedCount = 0
let errorCount = 0
targetFiles.forEach((filePath) => {
const fullPath = path.resolve(filePath)
if (fs.existsSync(fullPath)) {
if (processFile(fullPath)) {
modifiedCount++
}
} else {
console.warn(`⚠️ File not found: ${filePath}`)
errorCount++
}
})
console.log("\n📊 Summary:")
console.log(` Files processed: ${targetFiles.length}`)
console.log(` Files modified: ${modifiedCount}`)
console.log(` Errors: ${errorCount}`)
if (modifiedCount > 0) {
console.log("\n✅ Import replacement completed successfully!")
console.log("\n💡 Next steps:")
console.log(" 1. Review the changes with: git diff")
console.log(" 2. Run your tests to ensure everything works correctly")
console.log(" 3. Commit the changes if you're satisfied")
} else {
console.log(
"\n✅ No modifications needed - all imports are already correct!"
)
}
}
// Run if called directly
if (require.main === module) {
main()
}
module.exports = { processFile, getTargetFiles, main }
```
This script scans your project for files that import from `mikro-orm/{subpath}`, `awilix`, or `pg`, and replaces those imports with their new equivalents from `@medusajs/framework`. It handles both ES module `import` statements and CommonJS `require` statements in JavaScript and TypeScript files.
Next, run the following command in your terminal to make the script executable:
<Note title="Windows Users">
You can run the script using `node` without changing permissions.
</Note>
```bash
chmod +x replace-imports.js
```
Finally, execute the script with the following command:
```bash
node replace-imports.js
```
This will scan your project files, apply the necessary import replacements, and provide a summary of the changes made.
---
## Next Steps
After running the codemod, review the changes made to your codebase. You can use `git diff` to see the modifications. Additionally, run your tests to ensure everything works as expected.
If everything is working correctly, you can remove the `replace-imports.js` file from your project. You can also remove the following packages from your `package.json`, as they're now included in the `@medusajs/framework` package:
- `@mikro-orm/*` packages (for example, `@mikro-orm/core`, `@mikro-orm/migrations`, etc.)
- `awilix`
- `pg`
- `@opentelemetry/instrumentation-pg`
- `@opentelemetry/resources`
- `@opentelemetry/sdk-node`
- `@opentelemetry/sdk-trace-node`
@@ -40,13 +40,13 @@ Medusa uses [OpenTelemetry](https://opentelemetry.io/) for instrumentation and r
### Install Dependencies
Start by installing the following OpenTelemetry dependencies in your Medusa project:
<Note>
```bash npm2yarn
npm install @opentelemetry/sdk-node @opentelemetry/resources @opentelemetry/sdk-trace-node @opentelemetry/instrumentation-pg
```
As of [Medusa v2.11.0](https://github.com/medusajs/medusa/releases/tag/v2.11.0), OpenTelemetry dependencies are installed by default in new Medusa projects. If you're using an older version of Medusa, you need to install the `@opentelemetry/sdk-node`, `@opentelemetry/resources`, `@opentelemetry/sdk-trace-node`, and `@opentelemetry/instrumentation-pg` dependencies.
Also, install the dependencies relevant for the exporter you use. If you're using Zipkin, install the following dependencies:
</Note>
Before you start, you must install the dependencies relevant for the exporter you use. If you're using Zipkin, install the following dependencies:
```bash npm2yarn
npm install @opentelemetry/exporter-zipkin
@@ -63,8 +63,14 @@ if (process.env.TEST_TYPE === "integration:http") {
Next, create the `integration-tests/setup.js` file with the following content:
<Note>
As of [Medusa v2.11.0](https://github.com/medusajs/medusa/releases/tag/v2.11.0), MikroORM dependencies are included in the `@medusajs/framework` package. If you're using an older version of Medusa, change the require statement to `@mikro-orm/core`.
</Note>
```js title="integration-tests/setup.js"
const { MetadataStorage } = require("@mikro-orm/core")
const { MetadataStorage } = require("@medusajs/framework/@mikro-orm/core")
MetadataStorage.clear()
```
@@ -98,9 +98,48 @@ For example, the `VITE_MY_API_KEY` environment variable in the example above wil
## Environment Variables in Plugins
As explained in the [previous section](#environment-variables-in-production), environment variables are inlined into the build. This presents a limitation for plugins, where you can't use environment variables.
<Note>
Instead, only the following global variable is available in plugins:
Environment variable support in plugins is available starting [Medusa v2.11.0](https://github.com/medusajs/medusa/releases/tag/v2.11.0). Refer to the [Medusa versions prior to v2.11.0](#for-medusa-versions-prior-to-v2110) section for more details if you're using an earlier version.
</Note>
For plugins, you can use environment variables without a prefix. Then, Medusa applications that use the plugin can set the environment variable with the `PLUGIN_` prefix.
For example, you can create a widget in your plugin that uses the `MY_API_KEY` environment variable:
```tsx highlights={[["8"]]}
import { defineWidgetConfig } from "@medusajs/admin-sdk"
import { Container, Heading } from "@medusajs/ui"
const ProductWidget = () => {
return (
<Container className="divide-y p-0">
<div className="flex items-center justify-between px-6 py-4">
<Heading level="h2">API Key: {import.meta.env.MY_API_KEY}</Heading>
</div>
</Container>
)
}
export const config = defineWidgetConfig({
zone: "product.details.before",
})
export default ProductWidget
```
Then, in the Medusa application that uses the plugin, set the environment variable with the `PLUGIN_` prefix:
```bash
PLUGIN_MY_API_KEY=sk_123
```
The `MY_API_KEY` environment variable in the plugin will be replaced with the value of `PLUGIN_MY_API_KEY` during the build process of the Medusa application.
### Global Variables in Plugins
Plugins also have the following global variables available:
- `__BACKEND_URL__`: The URL of the Medusa backend, as set in the [Medusa configurations](../../../configurations/medusa-config/page.mdx#backendurl).
- `__BASE__`: The base path of the Medusa Admin. (For example, `/app`).
@@ -137,4 +176,14 @@ To fix possible type errors, create the file `src/admin/vite-env.d.ts` and add t
declare const __BACKEND_URL__: string
declare const __BASE__: string
declare const __STOREFRONT_URL__: string
```
```
### For Medusa versions prior to v2.11.0
<Details summaryContent="Instructions for Medusa versions prior to v2.11.0">
As explained in the [Environment Variables in Production section](#environment-variables-in-production), environment variables are inlined into the build. This presents a limitation for plugins, where you can't use environment variables.
Instead, you can use the [Plugin Global Variables](#global-variables-in-plugins) described above to access the backend URL, base path, and storefront URL.
</Details>
@@ -63,8 +63,14 @@ npx medusa db:generate blog
The `db:generate` command of the Medusa CLI accepts one or more module names to generate the migration for. It will create a migration file for the Blog Module in the directory `src/modules/blog/migrations` similar to the following:
<Note>
As of [Medusa v2.11.0](https://github.com/medusajs/medusa/releases/tag/v2.11.0), MikroORM dependencies are included in the `@medusajs/framework` package. If you're using an older version of Medusa, change the import statement to `@mikro-orm/migrations`.
</Note>
```ts
import { Migration } from "@mikro-orm/migrations"
import { Migration } from "@medusajs/framework/@mikro-orm/migrations"
export class Migration20241121103722 extends Migration {
@@ -37,8 +37,14 @@ You can also write migrations manually. To do that, create a file in the `migrat
For example:
<Note>
As of [Medusa v2.11.0](https://github.com/medusajs/medusa/releases/tag/v2.11.0), MikroORM dependencies are included in the `@medusajs/framework` package. If you're using an older version of Medusa, change the import statement to `@mikro-orm/migrations`.
</Note>
```ts title="src/modules/blog/migrations/Migration202507021059_create_author.ts"
import { Migration } from "@mikro-orm/migrations"
import { Migration } from "@medusajs/framework/@mikro-orm/migrations"
export class Migration202507021059 extends Migration {
@@ -53,7 +59,7 @@ export class Migration202507021059 extends Migration {
}
```
The migration class in the file extends the `Migration` class imported from `@mikro-orm/migrations`. In the `up` and `down` method of the migration class, you use the `addSql` method provided by MikroORM's `Migration` class to run PostgreSQL syntax.
The migration class in the file extends the `Migration` class imported from `@medusajs/framework/@mikro-orm/migrations`. In the `up` and `down` method of the migration class, you use the `addSql` method provided by MikroORM's `Migration` class to run PostgreSQL syntax.
In the example above, the `up` method creates the table `author`, and the `down` method drops the table if the migration is reverted.
@@ -27,6 +27,12 @@ So, to run database queries in a service:
For example, in your service, add the following methods:
<Note>
As of [Medusa v2.11.0](https://github.com/medusajs/medusa/releases/tag/v2.11.0), MikroORM dependencies are included in the `@medusajs/framework` package. If you're using an older version of Medusa, change the import statement to `@mikro-orm/knex`.
</Note>
export const methodsHighlight = [
["13", "getCount", "Retrieves the number of records in `my_custom` using the `count` method."],
["20", "getCountSql", "Retrieves the number of records in `my_custom` using the `execute` method."]
@@ -39,7 +45,7 @@ import {
MedusaContext,
} from "@medusajs/framework/utils"
import { Context } from "@medusajs/framework/types"
import { EntityManager } from "@mikro-orm/knex"
import { EntityManager } from "@medusajs/framework/@mikro-orm/knex"
class BlogModuleService {
// ...
@@ -66,7 +72,7 @@ class BlogModuleService {
You add two methods `getCount` and `getCountSql` that have the `InjectManager` decorator. Each of the methods also accept the `sharedContext` parameter which has the `MedusaContext` decorator.
The entity manager is injected to the `sharedContext.manager` property, which is an instance of [EntityManager from the @mikro-orm/knex package](https://mikro-orm.io/api/knex/class/EntityManager).
The entity manager is injected to the `sharedContext.manager` property, which is an instance of [EntityManager from the `@medusajs/framework/@mikro-orm/knex` package](https://mikro-orm.io/api/knex/class/EntityManager).
You use the manager in the `getCount` method to retrieve the number of records in a table, and in the `getCountSql` to run a PostgreSQL query that retrieves the count.
@@ -113,7 +119,7 @@ import {
MedusaContext,
} from "@medusajs/framework/utils"
import { Context } from "@medusajs/framework/types"
import { EntityManager } from "@mikro-orm/knex"
import { EntityManager } from "@medusajs/framework/@mikro-orm/knex"
class BlogModuleService {
// ...
@@ -174,7 +180,7 @@ import {
MedusaContext,
} from "@medusajs/framework/utils"
import { Context } from "@medusajs/framework/types"
import { EntityManager } from "@mikro-orm/knex"
import { EntityManager } from "@medusajs/framework/@mikro-orm/knex"
class BlogModuleService {
// ...
@@ -221,7 +227,7 @@ import {
MedusaContext,
} from "@medusajs/framework/utils"
import { Context } from "@medusajs/framework/types"
import { EntityManager } from "@mikro-orm/knex"
import { EntityManager } from "@medusajs/framework/@mikro-orm/knex"
class BlogModuleService {
// ...
@@ -380,7 +386,7 @@ import {
MedusaContext,
} from "@medusajs/framework/utils"
import { Context } from "@medusajs/framework/types"
import { EntityManager } from "@mikro-orm/knex"
import { EntityManager } from "@medusajs/framework/@mikro-orm/knex"
class BlogModuleService {
// ...
@@ -512,7 +518,7 @@ import {
MedusaContext,
} from "@medusajs/framework/utils"
import { Context } from "@medusajs/framework/types"
import { EntityManager } from "@mikro-orm/knex"
import { EntityManager } from "@medusajs/framework/@mikro-orm/knex"
class BlogModuleService {
// ...
@@ -582,7 +588,7 @@ The second parameter of the `baseRepository_.transaction` method is an object of
```ts highlights={[["24"]]}
// other imports...
import { EntityManager } from "@mikro-orm/knex"
import { EntityManager } from "@medusajs/framework/@mikro-orm/knex"
import {
InjectTransactionManager,
MedusaContext,
@@ -625,8 +631,8 @@ import {
MedusaContext,
} from "@medusajs/framework/utils"
import { Context } from "@medusajs/framework/types"
import { EntityManager } from "@mikro-orm/knex"
import { IsolationLevel } from "@mikro-orm/core"
import { EntityManager } from "@medusajs/framework/@mikro-orm/knex"
import { IsolationLevel } from "@medusajs/framework/@mikro-orm/core"
class BlogModuleService {
// ...
@@ -660,7 +666,7 @@ import {
MedusaContext,
} from "@medusajs/framework/utils"
import { Context } from "@medusajs/framework/types"
import { EntityManager } from "@mikro-orm/knex"
import { EntityManager } from "@medusajs/framework/@mikro-orm/knex"
class BlogModuleService {
// ...
@@ -152,6 +152,12 @@ Consider your have a MongoDB module that allows you to perform operations on a M
To connect to the database, you create the following loader in your module:
<Note>
As of [Medusa v2.11.0](https://github.com/medusajs/medusa/releases/tag/v2.11.0), Awilix dependencies are included in the `@medusajs/framework` package. If you're using an older version of Medusa, change the import statement to `awilix`.
</Note>
export const loaderHighlights = [
["5", "ModuleOptions", "Define a type for expected options."],
["13", "ModuleOptions", "Pass the option type as a type argument to `LoaderOptions`."],
@@ -163,7 +169,7 @@ export const loaderHighlights = [
```ts title="src/modules/mongo/loaders/connection.ts" highlights={loaderHighlights}
import { LoaderOptions } from "@medusajs/framework/types"
import { asValue } from "awilix"
import { asValue } from "@medusajs/framework/awilix"
import { MongoClient } from "mongodb"
type ModuleOptions = {
@@ -233,7 +239,7 @@ In the loader, you check first that these options are set before proceeding. The
After creating the client, you register it in the module's container using the container's `register` method. The method accepts two parameters:
1. The key to register the resource under, which in this case is `mongoClient`. You'll use this name later to resolve the client.
2. The resource to register in the container, which is the MongoDB client you created. However, you don't pass the resource as-is. Instead, you need to use an `asValue` function imported from the [awilix package](https://github.com/jeffijoe/awilix), which is the package used to implement the container functionality in Medusa.
2. The resource to register in the container, which is the MongoDB client you created. However, you don't pass the resource as-is. Instead, you need to use an `asValue` function imported from the [`@medusajs/framework/awilix` package](https://github.com/jeffijoe/awilix), which is the package used to implement the container functionality in Medusa.
### Use Custom Registered Resource in Module's Service
@@ -195,8 +195,14 @@ npx medusa db:generate blog
The `db:generate` command of the Medusa CLI accepts one or more module names to generate the migration for. It will create a migration file for the Blog Module in the directory `src/modules/blog/migrations` similar to the following:
<Note>
As of [Medusa v2.11.0](https://github.com/medusajs/medusa/releases/tag/v2.11.0), MikroORM dependencies are included in the `@medusajs/framework` package. If you're using an older version of Medusa, change the import statement to `@mikro-orm/migrations`.
</Note>
```ts
import { Migration } from "@mikro-orm/migrations"
import { Migration } from "@medusajs/framework/@mikro-orm/migrations"
export class Migration20241121103722 extends Migration {
@@ -70,17 +70,10 @@ A basic v2 project has the following dependencies in `package.json`:
"@medusajs/admin-sdk": "2.8.2",
"@medusajs/cli": "2.8.2",
"@medusajs/framework": "2.8.2",
"@medusajs/medusa": "2.8.2",
"@mikro-orm/core": "6.4.3",
"@mikro-orm/knex": "6.4.3",
"@mikro-orm/migrations": "6.4.3",
"@mikro-orm/postgresql": "6.4.3",
"awilix": "^8.0.1",
"pg": "^8.13.0"
"@medusajs/medusa": "2.8.2"
},
"devDependencies": {
"@medusajs/test-utils": "2.8.2",
"@mikro-orm/cli": "6.4.3",
"@swc/core": "1.5.7",
"@swc/jest": "^0.2.36",
"@types/jest": "^29.5.13",
@@ -107,25 +100,15 @@ The main changes are:
- `@medusajs/framework`
- `@medusajs/medusa`
- `@medusajs/test-utils` (as a dev dependency)
- You need to install the following extra packages:
- Database packages:
- `@mikro-orm/core@6.4.3`
- `@mikro-orm/knex@6.4.3`
- `@mikro-orm/migrations@6.4.3`
- `@mikro-orm/postgresql@6.4.3`
- `@mikro-orm/cli@6.4.3` (as a dev dependency)
- `pg^8.13.0`
- Framework packages:
- `awilix@^8.0.1`
- Development and Testing packages:
- `@swc/core@1.5.7`
- `@swc/jest@^0.2.36`
- `@types/node@^20.0.0`
- `jest@^29.7.0`
- `ts-node@^10.9.2`
- `typescript@^5.6.2`
- `vite@^5.2.11`
- `yalc@^1.0.0-pre.53`
- You need to install the following extra packages for development and testing:
- `@swc/core@1.5.7`
- `@swc/jest@^0.2.36`
- `@types/node@^20.0.0`
- `jest@^29.7.0`
- `ts-node@^10.9.2`
- `typescript@^5.6.2`
- `vite@^5.2.11`
- `yalc@^1.0.0-pre.53`
- Other packages, such as `@types/react` and `@types/react-dom`, are necessary for admin development and TypeScript support.
<Note>
@@ -10,7 +10,14 @@ In this chapter, you'll learn about the different modes of running a Medusa inst
## What is Worker Mode?
By default, the Medusa application runs both the server, which handles all incoming requests, and the worker, which processes background tasks, in a single process. While this setup is suitable for development, it is not optimal for production environments where background tasks can be long-running or resource-intensive.
By default, the Medusa application runs in `shared` mode, which runs:
- `server`: the application server that handles incoming requests to the application's API routes.
- `worker`: the worker that processes background tasks. This includes scheduled jobs and subscribers.
While this setup is suitable for development, it is not optimal for production environments where background tasks can be long-running or resource-intensive.
### Worker Mode in Production
In a production environment, you should deploy two separate instances of your Medusa application:
@@ -104,3 +111,27 @@ ADMIN_DISABLED=true
</CodeTab>
</CodeTabs>
---
## Dividing Resources in Cluster Mode
<Note>
The `--servers` and `--workers` options were introduced in [Medusa v2.11.0](https://github.com/medusajs/medusa/releases/tag/v2.11.0).
</Note>
When running Medusa in [cluster mode](!resources!/medusa-cli/commands/start#starting-medusa-in-cluster-mode), you can specify the number or percentage of instances that are servers or workers by passing the `--servers` and `--workers` options:
```bash
npx medusa start --cluster 4 --servers 25% --workers 75% # Use 4 CPU cores, with 25% as servers and 75% as workers
npx medusa start --cluster 4 --servers 1 --workers 3 # Use 4 CPU cores, with 1 as server and 3 as workers
npx medusa start --cluster 4 --servers 1 --workers 1 # Use 4 CPU cores, with 1 as server and 1 as worker (the remaining 2 will run in shared mode)
```
In the above snippet you can see the following examples:
- In the first example, 25% of the instances (1 out of 4) will run as servers, and 75% (3 out of 4) will run as workers.
- In the second example, 1 instance will run as a server, and 3 instances will run as workers.
- In the third example, 1 instance will run as a server, and 1 instance will run as a worker. The remaining 2 instances will run in shared mode