src/plugins.ts in your dashboard app and skip this section entirely — start with the Customization docs.
This section is for the ~10% of cases where you want to distribute dashboard extensions: as an open-source integration, an internal package shared across multiple host apps, or a SaaS-style commercial add-on.
What “plugin” means here
A dashboard plugin is:- An npm package — published, versioned, installed via
pnpm add @your-scope/your-plugin. - One side-effecting entry-point —
import '@your-scope/your-plugin'callsdefineDashboardPlugin({ ... })at module-load time, which registers nav entries, routes, slots, columns, etc. - Auto-discovered — the
"spree": { "dashboard": { "plugin": true } }marker in your package.json is all the host needs;spreeDashboardPlugin()finds every installed dependency carrying it, activates the entry-point, and scans your source for Tailwind classes so you never ship pre-built CSS. (Hosts can pass an explicitplugins: [...]array to opt out of discovery and whitelist instead.) - Translations-aware — your bundle ships JSON locale files and calls
i18n.addResourceBundle('en', 'translation', bundle, true, true)on import (keys nested under a top-leveladminobject). - Possibly Rails-aware — many plugins also ship a Rails engine alongside the dashboard package (new models, new API endpoints) so the dashboard has something to talk to.
src/plugins.ts you can also do from inside a plugin entry-point. The split between “in-app” and “plugin” is about packaging and distribution, not capability.
When to choose plugin over in-app
| Scenario | Approach |
|---|---|
| Single project, your own team | In-app customization |
| Two-three internal projects sharing the same extension | Internal npm package (still a plugin) |
| Open-source integration distributed via npm | Plugin |
| Commercial add-on with versioning + changelog | Plugin |
| One-off prototype, even at a client | In-app (you can extract later) |
src/plugins.ts into a plugin package later is a half-hour refactor — moving in the other direction is more painful.
What’s in this section
- Scaffolding —
spree plugin new <name>generates the monorepo - Publishing — package metadata, semver, the npm bits
- Distributing — what consumers do to install it
Reference
- Reference: Plugin example (
brandsrepo) — vendored reference implementation defineDashboardPluginsource

