We are thrilled to announce the integration of Modules into Medusa's architecture. Medusa’s mission is to equip developers with the resources necessary for constructing rich and unique commerce applications. With our work to modularize commerce, we make commerce logic portable to modern infrastructure while further improving customization and scalability options.
This article introduces Modules in Medusa, an overview of how it's currently being used, and what to expect in the future.
Understanding Modules
In software development, Modules are self-contained, reusable pieces of code that encapsulate specific functionality or features within an application. They foster separation of concerns, maintainability, and reusability by organizing code into smaller, independent units that can be easily managed, tested, and integrated with other modules.
Applying this concept to Medusa's architecture enables functional components (e.g., Medusa’s cart engine) to be extendable, entirely replaceable, or even capable of running independently of the main application.
A module comes with a definition containing information about its configuration and capabilities.
12345678910111213{key: string,registrationName: string,defaultPackage: string,label: string,canOverride: boolean,isRequired: boolean,dependencies: string[],defaultModuleDeclaration: {scope: "internal" | "external",resources: "shared" | "isolated",},}
Property Description Copy to clipboardkey
The key to register a module in your Copy to clipboardmedusa-config.js
file. Copy to clipboardregistrationName
The name of the main service of the module and its registration in the Copy to clipboardAwilix
dependency container. Copy to clipboarddefaultPackage
If the module comes with a default package, it will be added directly in the definition. If there's no default package, this value is Copy to clipboardfalse
. Copy to clipboardlabel
Readable label to identify the module. Copy to clipboardcanOverride
If Copy to clipboardtrue
, the module is replaceable. Copy to clipboardisRequired
If Copy to clipboardtrue
, the module is required. Copy to clipboarddependencies
Array of dependencies. The Copy to clipboardkey
property of other modules. defaultModuleDeclaration Copy to clipboardscope
The module’s scope can be internal or external. An internal module communicates with other services part of the same application. An external module communicates with other services via a separate protocol e.g. HTTP, rpc, etc. defaultModuleDeclarationCopy to clipboardresources
This is only applied to internal modules. A module that shares resources with the core uses the same database connection and the same Awilix container as the core. An isolated module will establish a separate database connection or uses a different data store and its Awilix container will only contain required dependencies from the core.
Modules are loaded in a manner akin to plugins. When the server starts, modules specified in Copy to clipboardmedusa-config.js
are loaded while adhering to their respective configurations.
The latest version, v1.8, comes with several modules ready to be installed:
- Inventory: This module manages inventory for items, supports item reservations, and handles stock levels across multiple locations.
- Stock Location: This module handles stock locations for stores with multiple warehouses.
- Event Bus (Local or Redis): A messaging module for publishing and subscribing to Medusa events. The default Copy to clipboard
module is ideal for local use, while the Redis-based
module is recommended for production environments. - Cache (Memory or Redis): A caching module designed to store cacheable parts of the application. The default Copy to clipboard
module stores data in memory, while the
module utilizes Redis for storage and is recommended for production use.
The Road Ahead
The development of Modules is progressing rapidly, with numerous intriguing features in the pipeline. Modules that rely on databases can already either share the same database connection as the main application or establish a separate connection. Similarly, developers can choose whether a module will utilize its own dedicated database or share the primary Medusa Core database.
Modules will also offer the flexibility to be used within any Nodejs application. Below is an example of the inventory module being initialized and used directly in a Next.js handler:
1234567891011121314151617181920import { initialize, InventoryServiceInitializeOptions } from "@medusajs/inventory";import { IInventoryService } from "@medusajs/types";import { NextApiRequest, NextApiResponse } from "next";let inventoryService = null;async function getInventoryService(): Promise<IInventoryService> {if (!inventoryService) {const options: InventoryServiceInitializeOptions = {database: {type: "postgres",url: `postgres://postgres:@localhost/inventory`,},};inventoryService = await initialize(options);}return inventoryService;}export default async (req: NextApiRequest, res: NextApiResponse) => {const { sku } = req.query as { sku: string };
Nonetheless, this method may constrain module development to the same technology stack as Medusa (Node.js, TypeScript, and JavaScript). To attain a truly composable commerce architecture, we plan to support external modules in the future. These external modules will operate as independent services, facilitating communication through HTTP/RPC.
By implementing this feature, not only will default Medusa modules be capable of functioning as standalone services, but developers will also be at liberty to craft their services using their preferred language or technology. Medusa will subsequently communicate effortlessly with these custom services.
You can learn more about Modules in our documentation. You can also Check out our roadmap in GitHub to follow along with plans for future modules and to see what the team is working on.