Brand Management
Brand management with product assignment and admin UI
@mgtalabs/medusa-brand
A commercial-grade Brand Management plugin for Medusa v2 — full CRUD with soft delete/restore, a one-brand-to-many-products relationship built on Medusa's official Module Link system, Admin and Store REST APIs, an Admin dashboard UI, and events other plugins can subscribe to.
Compatibility
Built and tested against Medusa 2.18.0. Requires Copy to clipboard@medusajs/medusa, Copy to clipboard@medusajs/framework, and the other packages listed under Copy to clipboardpeerDependencies to already be present in the consuming application (they are, for any standard Medusa v2 project).
Features
- Brand CRUD: create, update, soft delete + restore, permanent delete
- One brand → many products, via a Module Link (not a direct foreign key — see docs/architecture.md in the workspace for why)
- Assign a brand at product-creation time through the normal Admin product form (Copy to clipboard
additional_data.brand_id), or manage assignment after the fact from either side — the product's Admin page (see below), the brand's own detail page, or via the Brand's product endpoints directly - Storage-provider-agnostic logo/banner fields (plain URL + file id — works with local, S3, MinIO, Cloudinary, or any configured Medusa File Module provider)
- Bulk delete/restore
- Search (Copy to clipboard
qparam), status/featured filtering, pagination and sorting on all list endpoints - Admin dashboard: a Brands list, a Brand detail page (edit brand fields, plus a searchable/paginated multi-select product picker to assign, add, or remove products in bulk), a "Products" section in the Create Brand form to assign products at creation time, and a Product-detail widget for assigning, changing, or removing that product's brand from the product's own page
- Configurable via plugin options: Copy to clipboard
enableSEO, Copy to clipboardenableFeaturedBrands, Copy to clipboardlogoRequired - Events (Copy to clipboard
brand.created, Copy to clipboard.updated, Copy to clipboard.deleted, Copy to clipboard.restored) and workflow hooks (Copy to clipboardbrandCreated, Copy to clipboardbrandUpdated) for other plugins to build on
Installation
1npm install @mgtalabs/medusa-brand
Register it in your Medusa application's Copy to clipboardmedusa-config.ts:
12345678910111213module.exports = defineConfig({// ...plugins: [{resolve: "@mgtalabs/medusa-brand",options: {enableSEO: true,enableFeaturedBrands: true,logoRequired: false,},},],})
Then run migrations to create the Copy to clipboardbrand table and sync the product-brand link:
1npx medusa db:migrate
Configuration
Option Type Default Effect Copy to clipboardenableSEO Copy to clipboardboolean Copy to clipboardtrue Governs whether Copy to clipboardmeta_title/Copy to clipboardmeta_description are exposed in the admin form/API surface. The columns always exist regardless, to avoid schema drift if you flip this later. Copy to clipboardenableFeaturedBrands Copy to clipboardboolean Copy to clipboardtrue Governs whether the Copy to clipboardis_featured filter and Copy to clipboard/store/brands/featured are meaningfully used in your storefront. Copy to clipboardlogoRequired Copy to clipboardboolean Copy to clipboardfalse When Copy to clipboardtrue, brand creation is rejected (Copy to clipboardINVALID_DATA) if Copy to clipboardlogo_url isn't provided.
Admin API
All routes are under Copy to clipboard/admin and require the standard Medusa admin authentication — nothing extra to configure.
Method Path Description Copy to clipboardGET Copy to clipboard/admin/brands List brands. Query: Copy to clipboardq, Copy to clipboardstatus, Copy to clipboardis_featured, Copy to clipboardlimit, Copy to clipboardoffset, Copy to clipboardorder Copy to clipboardPOST Copy to clipboard/admin/brands Create a brand Copy to clipboardGET Copy to clipboard/admin/brands/:id Get a brand Copy to clipboardPOST Copy to clipboard/admin/brands/:id Update a brand Copy to clipboardDELETE Copy to clipboard/admin/brands/:id Soft delete (default); pass Copy to clipboard?permanent=true for a hard delete Copy to clipboardPOST Copy to clipboard/admin/brands/:id/restore Restore a soft-deleted brand Copy to clipboardPOST Copy to clipboard/admin/brands/batch Bulk delete/restore: Copy to clipboard{ delete?: string[], restore?: string[] } Copy to clipboardGET Copy to clipboard/admin/brands/:id/products List a brand's products (paginated) Copy to clipboardPOST Copy to clipboard/admin/brands/:id/products Assign products: Copy to clipboard{ product_ids: string[] } Copy to clipboardDELETE Copy to clipboard/admin/brands/:id/products Remove products: Copy to clipboard{ product_ids: string[] }
Brand fields: Copy to clipboardname, Copy to clipboardslug (auto-derived from Copy to clipboardname if omitted), Copy to clipboarddescription, Copy to clipboardshort_description, Copy to clipboardlogo_url, Copy to clipboardlogo_file_id, Copy to clipboardbanner_url, Copy to clipboardbanner_file_id, Copy to clipboardmeta_title, Copy to clipboardmeta_description, Copy to clipboardis_featured, Copy to clipboardsort_order, Copy to clipboardstatus (Copy to clipboardactive/Copy to clipboardinactive), Copy to clipboardmetadata.
Assigning a brand at product-creation time
123456POST /admin/products{"title": "...",..."additional_data": { "brand_id": "brand_123" }}
Store API
Public routes, gated by a publishable API key like any other store route.
Method Path Description Copy to clipboardGET Copy to clipboard/store/brands List active brands. Query: Copy to clipboardq, Copy to clipboardis_featured, Copy to clipboardlimit, Copy to clipboardoffset, Copy to clipboardorder Copy to clipboardGET Copy to clipboard/store/brands/featured Convenience alias for Copy to clipboard?is_featured=true Copy to clipboardGET Copy to clipboard/store/brands/:idOrSlug Get a brand by id or slug (same handler resolves either) Copy to clipboardGET Copy to clipboard/store/brands/:idOrSlug/products List a brand's products
Events
Event Payload Copy to clipboardbrand.created Copy to clipboard{ id } Copy to clipboardbrand.updated Copy to clipboard{ id } Copy to clipboardbrand.deleted Copy to clipboard{ id, permanent } Copy to clipboardbrand.restored Copy to clipboard{ id }
Subscribe from any plugin:
12345678910// src/subscribers/brand-created.tsimport type { SubscriberArgs, SubscriberConfig } from "@medusajs/framework"export default async function brandCreatedHandler({event: { data },}: SubscriberArgs<{ id: string }>) {// ...}export const config: SubscriberConfig = { event: "brand.created" }
Extension points
Beyond events, Copy to clipboardcreateBrandWorkflow and Copy to clipboardupdateBrandWorkflow expose hooks for synchronous, transactional extensibility:
12345import { createBrandWorkflow } from "@mgtalabs/medusa-brand/workflows/create-brand"createBrandWorkflow.hooks.brandCreated(async ({ brand }, { container }) => {// runs inside the same workflow transaction})
The Copy to clipboardproduct-brand Module Link itself is also queryable by any other plugin.
Known limitations
- Filtering core's Copy to clipboard
/admin/productsor Copy to clipboard/store/productsby Copy to clipboardbrand_iddirectly is not supported — Medusa doesn't document a way to extend a core route's query validator from a plugin. Use this plugin's own Copy to clipboard/admin/brands/:id/products/ Copy to clipboard/store/brands/:idOrSlug/productsinstead. - Copy to clipboard
/store/.../productsreturns whatever products are linked regardless of their own publish status — Medusa's Query layer doesn't support filtering by a linked model's property (confirmed against current docs), only by the link table's own columns. - HTTP-level integration tests for this plugin live in the consuming application's own test suite, not this package's — Copy to clipboard
@medusajs/test-utils's Copy to clipboardmedusaIntegrationTestRunnerhas an open upstream bug when configured at the plugin level (medusajs/medusa#11863). Module-level tests (Copy to clipboardmoduleIntegrationTestRunner) are unaffected and ship in Copy to clipboardsrc/modules/brand/__tests__/.
License
Proprietary — see the workspace root LICENSE. Free during the current evaluation period; see the workspace's Copy to clipboarddocs/architecture.md for the licensing/pricing model.

