Skip to content

Plugin System

Plugins are the primary extension mechanism in Rebase. They can:

  • Wrap the entire app with a provider (context, state management)
  • Add home page actions and widgets
  • Inject collection view components (toolbar, column builders)
  • Add form components (field builders, additional panels)
  • Inject or modify collections dynamically
interface RebasePlugin {
key: string; // Unique identifier
loading?: boolean; // Hold admin content until the plugin is ready
// UI contributions — a flat array, each entry naming its slot.
// This replaced the old per-area objects (homePage, collectionView, form).
slots?: SlotContribution[];
// HOC providers. `scope: "root"` wraps the whole admin below
// RebaseContext; `scope: "form"` wraps each entity form / edit view.
providers?: PluginProvider[];
// Behavioural (non-UI) hooks: collection modification and injection,
// column reordering, navigation entries.
hooks?: PluginHooks;
// Custom field rendering (e.g. data enhancement).
fieldBuilder?: FieldBuilderConfig;
// Views added to the navigation automatically.
views?: AppView[];
lifecycle?: PluginLifecycle;
}

Every one of these is optional except key. The full slot-name list lives on the Slots page.

Pass plugin instances to the navigation controller:

const dataEnhancementPlugin = useDataEnhancementPlugin();
const plugins = [dataEnhancementPlugin];
const navigationStateController = useBuildNavigationStateController({
plugins,
collections: () => collections,
// These four are required — the controller resolves navigation against them.
authController,
data,
collectionRegistryController,
urlController
});

Here’s a minimal plugin that adds a toolbar action to every collection:

import type { RebasePlugin } from "@rebasepro/admin-types";
function useMyPlugin(): RebasePlugin {
return {
key: "my_plugin",
// `slots` is a flat array of contributions, each naming its slot.
// See the Slots page for the full list of slot names.
slots: [
{ slot: "collection.actions", Component: MyToolbarAction }
],
// `fieldBuilder` is top-level and takes a `wrap` function that returns
// a *component* (or null to leave the default field alone) — it is not
// a render function and no longer lives under `form`.
fieldBuilder: {
wrap: ({ property }) =>
property.propertyConfig === "my_custom_field" ? MyCustomField : null
}
};
}

AI-powered field autocompletion:

import { useDataEnhancementPlugin } from "@rebasepro/plugin-ai";
const enhancementPlugin = useDataEnhancementPlugin();

Data enhancement

Plugins can dynamically add new collections:

hooks: {
// Receives the resolved collections and returns the full list to use.
injectCollections: (collections) => [...collections, auditLogCollection]
}

Plugins can modify existing collections:

hooks: {
// Receives one collection, returns the modified one.
// Use `modifyCollectionAsync` when the change needs a fetch.
modifyCollection: (collection) => ({
...collection,
properties: {
...collection.properties,
last_modified_by: {
type: "string",
name: "Modified By",
admin: { readOnly: true }
}
}
})
}