Skip to main content
If you’re customizing the dashboard for your own project, you don’t need a plugin. Drop the same code into 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:
  1. An npm package — published, versioned, installed via pnpm add @your-scope/your-plugin.
  2. One side-effecting entry-pointimport '@your-scope/your-plugin' calls defineDashboardPlugin({ ... }) at module-load time, which registers nav entries, routes, slots, columns, etc.
  3. 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 explicit plugins: [...] array to opt out of discovery and whitelist instead.)
  4. Translations-aware — your bundle ships JSON locale files and calls i18n.addResourceBundle('en', 'translation', bundle, true, true) on import (keys nested under a top-level admin object).
  5. 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.
That’s it. Plugins use the exact same registries as in-app customizations. Everything you can do in 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

ScenarioApproach
Single project, your own teamIn-app customization
Two-three internal projects sharing the same extensionInternal npm package (still a plugin)
Open-source integration distributed via npmPlugin
Commercial add-on with versioning + changelogPlugin
One-off prototype, even at a clientIn-app (you can extract later)
If you’re not sure: start in-app. Lifting 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

  • Scaffoldingspree plugin new <name> generates the monorepo
  • Publishing — package metadata, semver, the npm bits
  • Distributing — what consumers do to install it
If you haven’t yet, read the Customization section first. It’s where the registry API is documented; the plugin pages mostly cover packaging concerns.

Reference