- A Spree API server (your Spree store’s backend).
- Your dashboard app — the small Vite project that renders the admin. In a
create-spree-appproject it lives atapps/dashboard/; add it to an existing project withnpx spree add dashboard, or scaffold it anywhere withnpx spree add dashboard --templatepointing at your own copy. Start it withpnpm dev.
The 30-second example
Add an “Analytics” item to the dashboard sidebar. Step 1. Opensrc/plugins.ts — the starter ships this file already wired up — and register a nav entry:
Add the page
Step 3. Create the page component atsrc/pages/analytics.tsx:
src/plugins.ts:
/<store id>/analytics.
What just happened
defineDashboardPlugin registers extensions against the dashboard’s shared registries: nav, routes, slots, tables, settingsNav, formFields, and customFieldComponents. Your src/plugins.ts runs when the app boots (the starter’s main.tsx imports it), so everything is registered before the first render. These are the exact same APIs distributable plugins use — the only difference is packaging.
The custom route mounts under /<store id>/analytics. Routes registered this way are matched at navigation time, so they can even be registered lazily after boot.
Building a distributable plugin rather than customizing your own app? Ship pages as file routes instead — they compile into the app’s route tree, so links to them are type-checked. The registry form shown here is for in-app customization.
Next steps
- Navigation — sidebar entries, nesting under built-in menus, settings sub-nav, permission gating
- Routes — path patterns, params, permission fallback
- Slots — inject widgets into built-in pages without forking them
- Tables — define your own list page or extend built-in tables
- Translations — add i18n keys without colliding with the framework

