2.3. Modules

In this chapter, you’ll learn about modules and how to create them.

What is a Module?#

A module is a package of reusable commerce or architectural functionalities.

In Medusa, modules handle business logic in a class called a service, and define and manage data models that represent tables in the database.

Out of the box, Medusa comes with multiple pre-built modules for core commerce needs. For example, the Cart Module holds the data models and business logic for cart operations.

As you learn more about Medusa, you will see that Modules are central to customizations and integrations.


How to Create a Module?#

In this section, you'll build a module that has a MyCustom data model and a service to manage that data model. You'll then use the module's service in an API route to create a record of MyCustom.

Modules are created in a sub-directory of src/modules.

For example, create the directory src/modules/hello.

1. Create Data Model#

A data model represents a table in the database. It's created in a TypeScript or JavaScript file under the module's models directory.

For example, create the file src/modules/hello/models/my-custom.ts with the following content:

src/modules/hello/models/my-custom.ts
1import { model } from "@medusajs/framework/utils"2
3const MyCustom = model.define("my_custom", {4  id: model.id().primaryKey(),5  name: model.text(),6})7
8export default MyCustom

You define the data model using the define method of the model utility imported from @medusajs/framework/utils. It accepts two parameters:

  1. The first one is the name of the data model's table in the database. It should be snake-case.
  2. The second is an object, which is the data model's schema. The schema's properties are defined using the model's methods.

The example above defines the data model MyCustom with the properties id and name.

NoteData models automatically have the date properties created_at , updated_at , and deleted_at .

2. Create Service#

A module must define a service that implements its functionalities, such as managing the records of your custom data models in the database.

A service is a TypeScript or JavaScript class defined in the service.ts file at the root of your module's directory.

For example, create the file src/modules/hello/service.ts with the following content:

src/modules/hello/service.ts
1import { MedusaService } from "@medusajs/framework/utils"2import MyCustom from "./models/my-custom"3
4class HelloModuleService extends MedusaService({5  MyCustom,6}){7}8
9export default HelloModuleService

In the snippet above, your module's service extends a class generated by the MedusaService utility function, which is the service factory.

The MedusaService function accepts as a parameter an object of data models, and returns a class with generated methods for data-management Create, Read, Update, and Delete (CRUD) operations on those data models.

For example, HelloModuleService now has a createMyCustoms method to create MyCustom records, and retrieveMyCustom to retrieve a MyCustom record.

TipIf a module doesn't have data models, it doesn't need to extend MedusaService .
NoteYou'll learn more about the methods generated by the service factory in later chapters.

3. Export Module Definition#

A module must have an index.ts file in its root directory. The file exports the module's definition.

For example, create the file src/modules/hello/index.ts with the following content:

src/modules/hello/index.ts
1import HelloModuleService from "./service"2import { Module } from "@medusajs/framework/utils"3
4export const HELLO_MODULE = "helloModuleService"5
6export default Module(HELLO_MODULE, {7  service: HelloModuleService,8})

You use the Module function imported from @medusajs/framework/utils to create the module's definition. It accepts two parameters:

  1. The name that the module's main service is registered under (helloModuleService).
  2. An object with a required property service indicating the module's main service.

4. Add Module to Configurations#

The last step is to add the module in Medusa’s configurations.

In medusa-config.ts, add a modules property and pass in it your custom module:

medusa-config.ts
1module.exports = defineConfig({2  projectConfig: {3    // ...4  },5  modules: [6    {7      resolve: "./src/modules/hello",8    }9  ]10})

Its value is an array of objects, each having a resolve property, whose value is either a path to the module's directory, or an npm package’s name.

5. Generate Migrations#

A migration is a TypeScript or JavaScript file that defines database changes made by your module, such as creating the my_custom table for the MyCustom data model.

To generate a migration for the data models in your module, run the following command:

Terminal