Subchapter 2.6
checkpoints/checkpoint-module-links.mdMarkdown6 KBView on GitHub
This checkpoint verifies that you’ve successfully defined a module link between Brand and Product modules and synced it to the database.
Before proceeding, test your understanding:
Why do we use module links instead of directly importing from another module?
Module links maintain module isolation - modules don’t depend on each other’s code. The Brand Module doesn’t import Product entities, and Product Module doesn’t import Brand entities. This prevents circular dependencies and allows modules to be developed, tested, and deployed independently. Links are managed by Medusa’s linking layer, not by direct module-to-module references.
What does isList: true mean in a link definition?
isList: true means “one brand can have many products”. Without it (or with isList: false), the relationship would be one-to-one. In our case, we want one brand (e.g., “Nike”) to link to multiple products (shoes, shirts, etc.), so we use isList: true.
What is the purpose of BrandModule.linkable.brand?
linkable is a configuration object exported from each module that declares which entities can be linked to. BrandModule.linkable.brand tells Medusa “the Brand entity in the Brand Module can be used in links”.
Why do we put links in src/links directory and not inside a module?
Links are separate from modules to emphasize module independence. A link is a relationship managed by Medusa’s linking layer, not by either module. Keeping links in a separate directory makes it clear that they’re infrastructure concerns, not business logic. It also makes it easier to see all relationships in your application at a glance.
Let me verify your implementation. Please share the following:
Show me your src/modules/brand/index.ts file.
Key things to check:
Module()service property pointing to BrandServiceModules.BRAND constant for module name (or string “brand”)Show me if you created src/modules/brand/types/index.ts for module constants.
Key things to check:
MODULE_NAME = "brand"Modules.BRAND constant (if using Modules enum)Note: You can also define the constant directly in index.ts or use a string literal.
Show me your src/links/brand-product.ts file.
Key things to check:
defineLink from “@medusajs/framework/utils”Modules from “@medusajs/framework/utils” (for ProductModule reference)BrandModule from “../modules/brand”defineLink() with two arguments{
linkable: ProductModule.linkable.product,
isList: true,
}BrandModule.linkable.brandexport default defineLink(...)Run the database sync command:
npx medusa db:sync-linksExpected output: Should show that link was created successfully without errors. You should see output mentioning the brand-product relationship.
Run build to ensure no TypeScript errors:
npm run buildExpected output: Build should succeed without errors related to links or modules.
Symptom: db:sync-links command fails
Cause: Module not registered in medusa-config.ts, or server not recognizing the module
Fix:
medusa-config.ts modules arraynpm run devnpx medusa db:sync-linksVerify each of these steps:
src/links/ directorydb:sync-links command succeedsAt this point, you should understand:
Module Isolation:
┌─────────────┐ ┌──────────────┐
│ Brand │ │ Product │
│ Module │ │ Module │
│ │ │ │
│ - No direct imports between modules │
│ - Each module is independent │
└─────────────┘ └──────────────┘
│ │
└────────┬────────────────┘
│
┌──────▼────────┐
│ Link Layer │
│ (Medusa) │
│ │
│ Manages │
│ relationships│
└───────────────┘Why module links matter:
Once this checkpoint passes:
The link is now defined at the infrastructure level. Next, we’ll make it functional by consuming the productsCreated workflow hook to automatically link brands to products when products are created.
Ready to continue? Let me know when all checks pass, and we’ll move on to workflow hooks.