The React Dashboard is currently a Developer Preview — APIs may still change between releases.
In Spree 6 it will become the default Admin interface replacing the Spree 5 admin.
Packages
Dashboard consinsts of 3 NPM packages, each with a different purpose. You can import any of them in your host app or plugin package.
Most customization happens via
@spree/dashboard-core. You import its registries from your own host-app code (or from a separate plugin package) to add nav entries, routes, slot widgets, table columns, and translations.
You can also built your own dashboard using @spree/dashboard-ui primitives and @spree/dashboard-core registries, if you want to replace the default dashboard entirely. This is rare — most teams just add a few pages or cards to the existing dashboard.
Get the dashboard
Your copy of the dashboard is a small Vite app (the “host app”) that imports<Dashboard /> from @spree/dashboard — you own its package.json, Vite config, and a src/plugins.ts for customizations. Two ways to get one:
- New project:
npx create-spree-app my-store— answer Yes to “Include React Dashboard?” and it lands inapps/dashboard/, pointed at your API. - Existing project: run
npx spree add dashboardfrom your project root — same result.
cd apps/dashboard && npm run dev, open http://localhost:5173, and sign in with your admin email and password. No API keys to configure — admins authenticate interactively.
Choose your path
There are two ways to customize the dashboard. Both use the same APIs — the only difference is packaging.1. Customize in your host app (Recommended)
You’re building a Spree store and want a “Featured products” page or a custom card on every product detail. Edit your dashboard app directly — it ships asrc/plugins.ts file for exactly this (in a create-spree-app project the dashboard app lives at apps/dashboard/):
2. Ship a redistributable plugin
You’re building a feature that multiple Spree stores will install — a Brands gem, a Wishlists integration, a Stripe Tax connector. Package the customization as an npm module so any host app can install it with a singlepnpm add my-plugin.
This adds three concerns on top of in-app customization:
- Peer-dependency rules so your plugin’s
@spree/dashboard-coreresolves to the host’s instance (registries are module singletons — see Publishing) - Auto-discovery — the dashboard’s build finds every installed dependency carrying the
spree.dashboard.pluginmarker, activates it, and wires up its styling. Installing a plugin ispnpm add+ a dev-server restart; nothing to edit. See Distributing for how it works and the explicit-whitelist escape hatch. - File routes — a plugin ships its pages as TanStack file routes that get compiled into the app’s route tree, so links to plugin pages are fully type-checked. See Routes. (In-app customizations use the simpler
routes:registry instead, as above.) - A backend half — a Rails extension gem that ships the API endpoints your dashboard plugin calls
@spree/cli scaffolds the dashboard half for you:
Which one should I pick?
Use this rule of thumb:- Customize in-app if the feature is store-specific (your branding, your team’s workflow, your custom domain logic) or you don’t yet know whether others would want it. The cost to “promote” it to a plugin later is small.
- Ship a plugin if you’re certain others will install it (you’re publishing to the marketplace, your agency is rolling it out across clients, the feature has a clear standalone identity).
Reference
- Customization quickstart
- Plugin scaffolding
- Slots catalog — every named slot the dashboard exposes
@spree/dashboard-coreREADME — full extension API reference- Classic Admin extension model — for Spree 5.x

