name: general-create-extension-type description: Create a new extension type for the Umbraco backoffice extension registry. Use when adding a new type of extension that can be registered via manifests (e.g., a new dashboard type, a new sidebar app type, a new toolbar extension type). Any package can define extension types. allowed-tools: Read, Write, Edit, Grep, Glob
Create Extension Type
Create a new extension type for the Umbraco backoffice extension registry.
What you need from the user
- Type name — The
typestring used in manifests (e.g.,'dashboard','searchProvider') - Purpose — What this extension type does (determines which base interface to extend)
- Meta shape — What configuration the extension needs from consumers
- Whether it needs conditions — Should extensions of this type support conditional loading?
- Whether it has an element, API, or both — Does it render UI, provide logic, or both?
Files to create
All files go in the relevant feature directory (e.g., src/packages/my-package/my-feature/).
my-feature/
├── my-feature.extension.ts # Type definition + global declaration
├── my-feature-element.interface.ts # Element interface (if element-based)
└── types.ts # Meta interface (if needed)
Step 1: Choose the base manifest interface
| Your extension... | Extend from | Import |
|---|---|---|
| Renders a custom element | ManifestElement<T> |
@umbraco-cms/backoffice/extension-api |
| Provides an API class (no UI) | ManifestApi<T> |
@umbraco-cms/backoffice/extension-api |
| Has both element and API | ManifestElementAndApi<E, A> |
@umbraco-cms/backoffice/extension-api |
| Needs conditional loading | Also extend ManifestWithDynamicConditions<UmbExtensionConditionConfig> |
@umbraco-cms/backoffice/extension-api |
Step 2: Define the manifest interface
// my-feature.extension.ts
import type { ManifestElement, ManifestWithDynamicConditions } from '@umbraco-cms/backoffice/extension-api';
export interface MetaMyFeature {
label?: string;
// ... properties consumers configure via meta
}
export interface ManifestMyFeature
extends ManifestElement<UmbMyFeatureElement>,
ManifestWithDynamicConditions<UmbExtensionConditionConfig> {
type: 'myFeature';
meta: MetaMyFeature;
}
declare global {
interface UmbExtensionManifestMap {
umbMyFeature: ManifestMyFeature;
}
}
Key rules
- The
typeproperty must be a string literal type (notstring) - The key in
UmbExtensionManifestMapmust be unique across the entire codebase - The
declare globalblock is what makes the registry type-aware — without it, the type won't be recognized
Step 3: Define the element/API interface (if needed)
// my-feature-element.interface.ts
import type { UmbElement } from '@umbraco-cms/backoffice/element-api';
export interface UmbMyFeatureElement extends UmbElement {
// Properties/methods that implementations must provide
}
Step 4: If the type supports kinds
Add a union type for the base manifest plus kind-specific variants:
export interface ManifestMyFeatureButtonKind extends ManifestMyFeature {
type: 'myFeature';
kind: 'button';
meta: MetaMyFeatureButtonKind;
}
export interface MetaMyFeatureButtonKind extends MetaMyFeature {
icon: string;
}
// Union all variants in the global declaration
declare global {
interface UmbExtensionManifestMap {
umbMyFeature: ManifestMyFeature | ManifestMyFeatureButtonKind;
}
}
Step 5: Export from the package barrel
Add the type export to the package's index.ts:
export type * from './my-feature/my-feature.extension.js';
Use export type * since these are type-only exports.
Step 6: Register manifests that use this type
Verify the type works by creating a test manifest:
const manifest: UmbExtensionManifest = {
type: 'myFeature',
alias: 'Umb.MyFeature.Test',
name: 'Test My Feature',
element: () => import('./my-feature-test.element.js'),
meta: {
label: 'Test',
},
};
TypeScript should provide autocomplete for type and validate meta against MetaMyFeature.
Checklist
- Manifest interface extends the correct base (
ManifestElement,ManifestApi, orManifestElementAndApi) -
typeproperty is a string literal, notstring -
declare globalblock adds toUmbExtensionManifestMapwith a unique key - Meta interface is defined separately and exported
- Element/API interface is defined if the type renders UI or provides logic
- If kinds are supported: kind-specific interfaces extend the base with literal
kindproperty - Type is exported from the package's
index.ts - Compiles:
npm run compile