@mercurjs/adminor@mercurjs/vendoritself,- each plugin in
medusa-configpluginsorder, from its built.medusa/server/src/<admin|vendor>/index.mjs, - your Medusa project’s
src/adminorsrc/vendorfolder (next tomedusa-config.ts), - the panel app’s own
srcfolder.
id
replaces it, a translation key overrides it, and a layout preference overrides it field by field. Every
layer uses the same folders: routes/, widgets/, custom-fields/, layouts/, i18n/ and a
_layouts.ts file.
Pages expose named entries
A detail or list page renders aLayoutComposer. It names the zone widgets target, the layout it uses,
and gives each section a stable entry id:
core:ProductGeneralSection, core:MetadataSection and so on;
widgets become widget:<id>. Use the same component on your own pages and the build emits their zones and
entry ids into extension-targets.d.ts, so the next layer gets autocompletion for them.
Place a widget
zone is the page prefix or one of its sections. section and order place the widget among the page’s
entries; core entries sit at order 0, so a negative order renders before them and no order renders after.
replace takes the slot of a page entry. The widget receives renderDefault to render what it replaced:
product.detail.side.before and .after zones still work and map to the first and last
position of that section.
Hide, reorder and move entries: _layouts.ts
A layer’s _layouts.ts holds per-zone preferences that apply to everyone. The sidebars are zones too
(nav.main, nav.settings) with nav:<path> entries, which replaces _navigation.ts.
Override a page
Apage.tsx at a path an earlier layer already serves replaces it. The component receives renderDefault,
which renders the page it replaced:
Block the panel behind a flow
There is no app-wrapper seam, as in Medusa. A flow every member must complete before using the panel (terms acceptance, a verification step) is a page plus a redirect: aroutes/<flow>/page.tsx with
config.public = true so it renders in the bare public layout, and a widget on the topbar zone that
checks the status with useQuery and navigates to the page while the flow is outstanding. The API keeps
enforcing the rule with a 403 for everything else.
Register a layout
A file underlayouts/ registers a layout other pages can pick. Augment LayoutSectionRegistry so the
sections prop is typed.