Skip to main content

Migrating from Admin UI

If you have existing extensions to the legacy Angular-based Admin UI, you will want to migrate to the new Dashboard to enjoy an improved developer experience, many more customization options, and ongoing support from the Vendure team.

Warning

The Angular Admin UI will not be maintained after July 2026. Until then, we will continue patching critical bugs and security issues. Community contributions will always be merged and released.

Running In Parallel

A recommended approach to migrating is to run both the Admin UI and the new Dashboard in parallel. This allows you to start building new features right away with the new Dashboard while maintaining access to existing features that have not yet been migrated.

To do so, follow the instructions to set up the Dashboard. Both plugins can now be used simultaneously without any special configuration.

AI-Assisted Migration

We highly recommend using AI tools such as Claude Code, Codex etc to assist with migrations from the legacy Angular-based UI extensions to the new React-based Dashboard.

Info

The results of AI-assisted migration are heavily dependent on the model that you use. We tested with Claude Code using Sonnet 4.5 & Codex using gpt-5-codex

In our testing, we were able to perform complete migrations quickly using the following approach:

  1. Use the provided prompt or Claude skill and specify which plugin you wish to migrate (do 1 at a time)
  2. Allow the AI tool to complete the migration
  3. Manually clean up & fix any issues that remain

Using this approach we were able to migrate complete plugins involving list/details views, widgets, and custom field components in around 20-30 minutes.

Full Prompt

Give a prompt like this to your AI assistant and make sure to specify the plugin by path, i.e.:

Migrate the plugin at @src/plugins/my-plugin/ 
to use the new dashboard.

Then paste the following prompt in full:

Md
Tip

The full prompt is quite large, so it can make sense to first clear the current LLM context, e.g. with /clear in Claude Code or /new in Codex CLI

Claude Skills

If you use Claude Code, you can use Agent Skills to set up a specialized skill for migrating plugins. This has the advantage that you do not need to continually paste in the full prompt, and it can also be potentially more token-efficient.

To set up a the skill, run this from the root of your project:

npx degit vendure-ecommerce/vendure/.claude/skills#minor .claude/skills

This command uses degit to copy over the vendure-dashboard-migration skill to your local ./claude/skills directory.

You can then have Claude Code use the skill with a prompt like:

Use the vendure-dashboard-migration skill to migrate 
@src/plugins/my-plugin to use the dashboard
Note

The individual files in the skill contain the exact same content as the full prompt above, but are more easily reused and can be more token-efficient

Manual Cleanup

It is very likely you'll still need to do some manual cleanup after an AI-assisted migration. You might run into things like:

  • Non-optimum styling choices
  • Issues with the tsconfig setup not being perfectly implemented.
  • For more complex repo structures like a monorepo with plugins as separate libs, you may need to manually implement the initial setup of the config files.

Manual Migration

If you would rather do a full manual migration, you should first follow the Dashboard Getting Started guide and the Extending the Dashboard guide.

The remainder of this document details specific features, and how they are now implemented in the new Dashboard.

Forms

Forms in the Angular Admin UI used vdr-form-field components within a form-grid class. In the Dashboard, forms use FormFieldWrapper with react-hook-form, wrapped in either DetailFormGrid for grid layouts or div containers with space-y-6 for vertical spacing.

Admin UIDashboardImported FromNotes
vdr-form-fieldFormFieldWrapper@vendure/dashboardUses react-hook-form
form-grid (class)DetailFormGrid@vendure/dashboardFor grid layouts
vdr-rich-text-editorRichTextInput@vendure/dashboard
-Input@vendure/dashboardBasic text input
FormGroupuseFormreact-hook-formForm state management
Tsx

Custom Field Inputs

Custom field inputs now use the DashboardFormComponent type and are registered via customFormComponents.customFields in the Dashboard extension definition. Components receive value, onChange, and name props, and can use useFormContext() to access field state and errors.

Admin UIDashboardImported FromNotes
FormInputComponent<T>DashboardFormComponent@vendure/dashboardType for custom field components
registerFormInputComponent()customFormComponents.customFields@vendure/dashboardRegistration method
formControl (prop)value, onChange, name (props)-Component receives these props
-useFormContext()react-hook-formAccess field state and errors
Tsx

List Pages

List pages migrate from TypedBaseListComponent to the ListPage component. The ListPage automatically generates columns from the GraphQL query fields. Use customizeColumns to customize specific columns (e.g., linking with DetailPageButton), defaultVisibility to control which columns show by default, and defaultColumnOrder to set column order.

Admin UIDashboardImported FromNotes
TypedBaseListComponentListPage@vendure/dashboardMain list component
vdr-data-table-2ListPage@vendure/dashboardAuto-generates columns
vdr-dt2-columncustomizeColumns-Prop on ListPage
[hiddenByDefault]defaultVisibility-Prop on ListPage
registerRouteComponent()DashboardRouteDefinition@vendure/dashboardRoute registration
[routerLink]DetailPageButton@vendure/dashboardFor linking to detail pages
Tsx

Important: When using defaultVisibility, only specify visible columns with true. The id, createdAt, and updatedAt columns are handled automatically. If a custom cell function accesses fields other than the one being rendered, declare them in meta.dependencies.

Detail Pages

Detail pages migrate from TypedBaseDetailComponent to the useDetailPage hook. The hook handles form initialization, entity loading, and mutations. Use detailPageRouteLoader for the route loader, and structure the page with Page, PageActionBar, PageLayout, PageBlock, and DetailFormGrid components.

Admin UIDashboardImported FromNotes
TypedBaseDetailComponentuseDetailPage()@vendure/dashboardHook for detail page logic
this.init()useDetailPage()@vendure/dashboardAutomatic initialization
this.entity$entity-Returned from useDetailPage
FormBuilderform-Returned from useDetailPage
dataService.mutate()submitHandler-Returned from useDetailPage
vdr-page-detail-layoutPageLayout@vendure/dashboardLayout component
vdr-page-blockPageBlock@vendure/dashboardContent block
registerRouteComponent()detailPageRouteLoader()@vendure/dashboardRoute loader helper
Tsx

Important: PageBlock already renders as a card, so never nest Card components inside it. Use refreshEntity to manually reload entity data after mutations. Ensure vertical spacing of 6 units for components not in DetailFormGrid.

Nav menu items are now configured via the navMenuItem property on route definitions within the routes array. Specify sectionId (e.g., 'catalog'), unique id, and title.

Admin UIDashboardImported FromNotes
addNavMenuSection()navMenuItem-Defined on route in routes array
labeltitle-Display text
routerLinkpath-Route path
icon--Not supported in Dashboard
Tsx

Action Bar Items

Action bar items migrate from addActionBarItem to the actionBarItems array in the Dashboard extension. Each item specifies a pageId and a component function that receives context.

Admin UIDashboardImported FromNotes
addActionBarItem()actionBarItems-Array in defineDashboardExtension
locationIdpageId-Identifies target page
label--Render button/component directly
icon-lucide-reactUse icon components in button
routerLinkLink / useNavigate()@tanstack/react-routerFor navigation
Tsx

Custom Detail Components (Page Blocks)

Custom detail components (Angular CustomDetailComponent) are now implemented as page blocks via the pageBlocks array. Each block specifies id, title, location (pageId, column, position), and a component function that receives context with entity and form access.

Admin UIDashboardImported FromNotes
CustomDetailComponentpageBlocks-Array in defineDashboardExtension
entity$ (Observable)context.entity-Available in component function
detailFormcontext.form-Available in component function
registerCustomDetailComponent()pageBlocks[].location-Positioning configuration
Tsx

Page Tabs

Page tabs (registerPageTab) are not supported in the Dashboard. Consider alternative approaches such as creating a new route or using page blocks.

Admin UIDashboardImported FromNotes
registerPageTab()--Not supported; use routes or page blocks instead

Widgets

Dashboard widgets migrate from registerDashboardWidget to the widgets array. Each widget specifies id, name, component, and defaultSize. Widget components can use useWidgetFilters() and useLocalFormat() hooks, and should wrap content in DashboardBaseWidget.

Admin UIDashboardImported FromNotes
registerDashboardWidget()widgets-Array in defineDashboardExtension
titlename-Widget display name
loadComponentcomponent-Widget component function
supportedWidthsdefaultSize-Object with w and h properties
-DashboardBaseWidget@vendure/dashboardWrapper component for widgets
-useWidgetFilters()@vendure/dashboardAccess date range filters
-useLocalFormat()@vendure/dashboardFormatting utilities
Tsx
Was this chapter helpful?
Report Issue
Edited Feb 23, 2026·Edit this page