A marketplace is an online commerce store that allows different vendors to sell their products within the same commerce system. Customers can purchase products from any of these vendors, and vendors can manage their orders separately.
Build a marketplaceCustomize the backend and handle events to build a marketplace.
By default, entities like users, products, or orders aren't associated with a store, as it's assumed there's one store in Medusa. For a marketplace, each of these entities should be associated with their respective stores.
To associate these entities with the StoreCopy to Clipboard entity, you need to extend and customize entities created in the Medusa core package @medusajs/medusaCopy to Clipboard, such as the UserCopy to Clipboard entity, to add a relation to the StoreCopy to Clipboard entity.
For example, to associate the UserCopy to Clipboard entity with the StoreCopy to Clipboard entity, create the file src/models/user.tsCopy to Clipboard with the following content:
src/models/user.ts
import{ Column, Entity, Index, JoinColumn, ManyToOne, }from"typeorm" import{ User as MedusaUser, }from"@medusajs/medusa" import{ Store }from"./store" @Entity() exportclassUserextendsMedusaUser{ @Index("UserStoreId") @Column({ nullable:true}) store_id?:string @ManyToOne(()=> Store,(store)=> store.members) @JoinColumn({ name:"store_id", referencedColumnName:"id"}) store?: Store }
Report Incorrect CodeCopy to Clipboard
Then, you need to extend the UserRepositoryCopy to Clipboard to point to your extended entity. To do that, create the file src/repositories/user.tsCopy to Clipboard with the following content:
src/repositories/user.ts
import{ User }from"../models/user" import{ dataSource, }from"@medusajs/medusa/dist/loaders/database" import{ UserRepository as MedusaUserRepository, }from"@medusajs/medusa/dist/repositories/user" exportconst UserRepository = dataSource .getRepository(User) .extend({ ...Object.assign( MedusaUserRepository, { target: User } ), }) exportdefault UserRepository
Report Incorrect CodeCopy to Clipboard
Next, you need to create a migration that reflects the changes on the UserCopy to Clipboard entity in your database. To do that, run the following command to create a migration file:
This creates a file in the src/migrationsCopy to Clipboard directory of the format <TIMESTAMP>_add-user-store-id.tsCopy to Clipboard. Replace the upCopy to Clipboard and downCopy to Clipboard methods in that file with the methods here:
src/migrations/<TIMESTAMP>_add-user-store-id.ts
// ... exportclassAddUserStoreId1681287255173 implementsMigrationInterface{ // ... publicasyncup(queryRunner: QueryRunner):Promise<void>{ await queryRunner.query( `ALTER TABLE "user" ADD "store_id" character varying` ) await queryRunner.query( `CREATE INDEX "UserStoreId" ON "user" ("store_id")` ) } publicasyncdown(queryRunner: QueryRunner):Promise<void>{ await queryRunner.query( `DROP INDEX "public"."UserStoreId"` ) await queryRunner.query( `ALTER TABLE "user" DROP COLUMN "store_id"` ) } }
Report Incorrect CodeCopy to Clipboard
Finally, to reflect these changes and start using them, buildCopy to Clipboard your changes and run migrations with the following commands:
npm
Yarn
pnpm
npm run build npx @medusajs/medusa-cli migrations run
Report Incorrect CodeCopy to Clipboard
yarn build npx @medusajs/medusa-cli migrations run
Report Incorrect CodeCopy to Clipboard
pnpm run build npx @medusajs/medusa-cli migrations run
Report Incorrect CodeCopy to Clipboard
You can extend other entities in a similar manner to associate them with a store.
Throughout your development, you'll likely need access to the logged-in user. For example, you'll need to know which user is logged in to know which store to associate a new product with.
After associating entities with stores, you'll need to customize how certain data management functionalities are implemented in the Medusa core package.
For example, when a new user is created, you need to ensure that it's associated either with a new store or with the store of the logged-in user. Another example is associating a new product with the logged-in user's store.
You can customize these functionalities by extending services. Services are classes that contain helper methods specific to an entity. For example, the UserServiceCopy to Clipboard is used to manage functionalities related to the UserCopy to Clipboard entity, such as creating a user.
You can also extend services if you need to customize a functionality implemented in a service for other reasons.
In the createCopy to Clipboard method of this extended service, you create a new store if the user being created doesn't have a store associated with it.
You can then test out your customization by running the buildCopy to Clipboard command and starting the backend:
While implementing your marketplace, you'll typically need to listen to certain events then perform actions asynchronously. For example, you can listen to the order.placedCopy to Clipboard event and, when triggered, create child orders of the order, separating ordered items by their associated store.
To listen to events, you need to create Subscribers that subscribe a handler method to an event. In that handler method, you can implement the desired functionality.
Payment and fulfillment providers can be added through plugins or directly in your project. You can either create your own provider, use one of Medusa's official plugins, or use community plugins.
Payment and fulfillment providers are associated with regions, which are not associated with a store, by default. If you want to allow each store to specify its own payment and fulfillment providers, you'll need to associate the region with a store.
Medusa provides a Next.js Starter Template that you can use with Medusa. Since you've customized your Medusa project, you'll need to either customize the existing Next.js Starter Template, or create a custom storefront.
Our documentation includes deployment guides for a basic Medusa backend. You should be able to follow it to deploy your customized marketplace, as well.