Skip to main content
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.
The React Dashboard is a React single-page application (SPA) that talks to the Spree Admin API. It can be distributed with the Spree API or as a standalone npm package, and it can be extended with plugins. The dashboard is built with modern React libraries and patterns, including:
LayerChoice
Build & devVite
RoutingTanStack Router (file-based, type-safe)
Data fetchingTanStack Query
FormsReact Hook Form + Zod
UI primitivesshadcn/ui + Base UI + Tailwind CSS
Iconslucide-react
ChartsRecharts
Rich textTiptap
NotificationsSonner
Lint & formatBiome

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.
PackageWhat it containsWhen you touch it
@spree/dashboard-uiDesign system: shadcn primitives + headless composed components (PageHeader, ResourceLayout, ResourceTable’s rendering layer, etc.) + design tokensBuilding custom UI — primitives + compounds you can drop anywhere
@spree/dashboard-coreFramework: registries (nav, route, slot, table, settings-nav), providers (auth, permission, store), admin SDK client, infra hooks, the defineDashboardPlugin APIExtending the admin — every customization API lives here
@spree/dashboardThe deployable SPA: routes, resource hooks, schemas, locale strings, app shellReplacing or restyling specific routes (rare)
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 in apps/dashboard/, pointed at your API.
  • Existing project: run npx spree add dashboard from your project root — same result.
Either way: 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. 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 a src/plugins.ts file for exactly this (in a create-spree-app project the dashboard app lives at apps/dashboard/):
That’s the entire setup. No npm publishing, no peer dependencies, no build configuration — you’re inside the app’s own build, so styling and hot reload just work. Most teams stop here. → Start at the customization quickstart.

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 single pnpm add my-plugin. This adds three concerns on top of in-app customization:
  • Peer-dependency rules so your plugin’s @spree/dashboard-core resolves 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.plugin marker, activates it, and wires up its styling. Installing a plugin is pnpm 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
The @spree/cli scaffolds the dashboard half for you:
→ Start at the plugin scaffolding guide.

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).
When in doubt, customize in-app first. The migration path to a plugin is mechanical — same APIs, just wrapped in their own package.

Reference