| name | general-create-repository |
| description | Create or extend a repository in the Umbraco backoffice. Covers detail (CRUD), item (batch lookup), collection (paginated list), and action-specific (publish, duplicate, move, etc.) repositories. Use when the user says "create a repository", "add a data source", or when a feature needs to fetch or post data. Each repository type has its own template โ pick the right one based on the operation. |
| allowed-tools | Read, Write, Edit, Grep, Glob |
Create Repository
Create or extend a repository and its data source for an entity feature in the Umbraco backoffice.
Foundational documentation
Read these before creating a repository โ they define the conventions this skill builds on:
- Repositories โ Repository categories, file structure, naming, extension registration, when to use which type
- Data Flow โ Full data flow chain, tryExecute, model mapping, store direction
- Package Development โ Folder conventions, vertical slices, public API rules
What you need from the user
- Entity name โ singular, kebab-case (e.g.,
webhook, document, data-type)
- Repository type โ
detail, item, collection, or action-specific
- Package path โ which package directory (e.g.,
src/packages/webhook/webhook/)
Additional for action-specific: 4. Action name โ what the operation does (e.g., duplicate, move-to, publishing, culture-and-hostnames) 5. Methods โ what operations the repository exposes
Choosing the right type
See Repositories โ When to Create Which for the decision matrix.
Option A: Detail Repository
The most common repository type. Handles full CRUD lifecycle with store caching.
Prerequisites
- Entity type constant in
entity.ts
- Detail model type in
types.ts (must extend UmbEntityModel โ needs entityType and unique fields)
- Generated API client available for the entity
Files to create
{package-path}/repository/detail/
โโโ {entity}-detail.repository.ts
โโโ {entity}-detail.server.data-source.ts
โโโ {entity}-detail.store.ts
โโโ {entity}-detail.store.context-token.ts
โโโ constants.ts
โโโ manifests.ts
Step 1: Create store context token
File: {entity}-detail.store.context-token.ts
import type { UmbDetailStoreBase } from '@umbraco-cms/backoffice/store';
import type { Umb{EntityName}DetailModel } from '../../types.js';
import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
export const UMB_{ENTITY}_DETAIL_STORE_CONTEXT = new UmbContextToken<UmbDetailStoreBase<Umb{EntityName}DetailModel>>(
'Umb{EntityName}DetailStore',
);
Step 2: Create store
File: {entity}-detail.store.ts
import type { Umb{EntityName}DetailModel } from '../../types.js';
import { UMB_{ENTITY}_DETAIL_STORE_CONTEXT } from './{entity}-detail.store.context-token.js';
import { UmbDetailStoreBase } from '@umbraco-cms/backoffice/store';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
export class Umb{EntityName}DetailStore extends UmbDetailStoreBase<Umb{EntityName}DetailModel> {
constructor(host: UmbControllerHost) {
super(host, UMB_{ENTITY}_DETAIL_STORE_CONTEXT);
}
}
export { Umb{EntityName}DetailStore as api };
Step 3: Create server data source
File: {entity}-detail.server.data-source.ts
The data source maps between server API types and domain models. See Data Flow for context on how this fits in the chain.
import type { Umb{EntityName}DetailModel } from '../../types.js';
import { UMB_{ENTITY}_ENTITY_TYPE } from '../../entity.js';
import { UmbId } from '@umbraco-cms/backoffice/id';
import type { UmbDetailDataSource } from '@umbraco-cms/backoffice/repository';
import { {EntityName}Service } from '@umbraco-cms/backoffice/external/backend-api';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import { tryExecute } from '@umbraco-cms/backoffice/resources';
export class Umb{EntityName}DetailServerDataSource implements UmbDetailDataSource<Umb{EntityName}DetailModel> {
#host: UmbControllerHost;
constructor(host: UmbControllerHost) {
.#host = host;
}
() {
: {} = {
: {}_ENTITY_TYPE,
: .(),
: ,
...preset,
};
{ data };
}
() {
(!unique) ();
{ data, error } = (
.#host,
{}.{}({ : { : unique } }),
);
(error || !data) {
{ error };
}
: {} = {
: {}_ENTITY_TYPE,
: data.,
: data. ?? ,
};
{ : model };
}
() {
(!model) ();
body = {
: model.,
: model.,
};
{ data, error } = (
.#host,
{}.{}({ body }),
);
(data) {
.(data );
}
{ error };
}
() {
(!model.) ();
body = {
: model.,
};
{ error } = (
.#host,
{}.{}({ : { : model. }, body }),
);
(!error) {
.(model.);
}
{ error };
}
() {
(!unique) ();
(
.#host,
{}.{}({ : { : unique } }),
);
}
}
Important: Find the actual generated API service name and method names by checking @umbraco-cms/backoffice/external/backend-api. The names above are illustrative โ the real generated service may differ.
Step 4: Create repository
File: {entity}-detail.repository.ts
import type { Umb{EntityName}DetailModel } from '../../types.js';
import { Umb{EntityName}DetailServerDataSource } from './{entity}-detail.server.data-source.js';
import { UMB_{ENTITY}_DETAIL_STORE_CONTEXT } from './{entity}-detail.store.context-token.js';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import { UmbDetailRepositoryBase } from '@umbraco-cms/backoffice/repository';
export class Umb{EntityName}DetailRepository extends UmbDetailRepositoryBase<Umb{EntityName}DetailModel> {
constructor(host: UmbControllerHost) {
super(host, Umb{EntityName}DetailServerDataSource, UMB_{ENTITY}_DETAIL_STORE_CONTEXT);
}
}
export { Umb{} api };
Step 5: Create constants
File: constants.ts
export const UMB_{ENTITY}_DETAIL_REPOSITORY_ALIAS = 'Umb.Repository.{EntityName}.Detail';
export const UMB_{ENTITY}_DETAIL_STORE_ALIAS = 'Umb.Store.{EntityName}.Detail';
Step 6: Create manifests
File: manifests.ts
import { UMB_{ENTITY}_DETAIL_REPOSITORY_ALIAS, UMB_{ENTITY}_DETAIL_STORE_ALIAS } from './constants.js';
import { Umb{EntityName}DetailStore } from './{entity}-detail.store.js';
export const manifests: Array<UmbExtensionManifest> = [
{
type: 'repository',
alias: UMB_{ENTITY}_DETAIL_REPOSITORY_ALIAS,
name: '{EntityName} Detail Repository',
api: () => import('./{entity}-detail.repository.js'),
},
{
type: 'store',
alias: UMB_{ENTITY}_DETAIL_STORE_ALIAS,
name: '{EntityName} Detail Store',
api: Umb{EntityName}DetailStore,
},
];
Step 7: Wire manifests into parent
Import and spread in the parent module's manifests.ts:
import { manifests as detailRepositoryManifests } from './repository/detail/manifests.js';
export const manifests: Array<UmbExtensionManifest> = [
...detailRepositoryManifests,
];
Detail repository checklist
Option B: Item Repository
For batch-fetching lightweight display info (name, icon, entity type) by unique IDs. Used by pickers, reference lists, and breadcrumbs.
Prerequisites
- Item model type in
types.ts (needs unique field)
- Generated API client with a batch/list endpoint
Files to create
{package-path}/item/repository/
โโโ {entity}-item.repository.ts
โโโ {entity}-item.server.data-source.ts
โโโ {entity}-item.store.ts
โโโ {entity}-item.store.context-token.ts
โโโ constants.ts
โโโ manifests.ts
Step 1: Create item store context token
File: {entity}-item.store.context-token.ts
import type { UmbItemStore } from '@umbraco-cms/backoffice/store';
import type { Umb{EntityName}ItemModel } from '../../types.js';
import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
export const UMB_{ENTITY}_ITEM_STORE_CONTEXT = new UmbContextToken<UmbItemStore<Umb{EntityName}ItemModel>>(
'Umb{EntityName}ItemStore',
);
Step 2: Create item store
File: {entity}-item.store.ts
import type { Umb{EntityName}ItemModel } from '../../types.js';
import { UMB_{ENTITY}_ITEM_STORE_CONTEXT } from './{entity}-item.store.context-token.js';
import { UmbItemStoreBase } from '@umbraco-cms/backoffice/store';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
export class Umb{EntityName}ItemStore extends UmbItemStoreBase<Umb{EntityName}ItemModel> {
constructor(host: UmbControllerHost) {
super(host, UMB_{ENTITY}_ITEM_STORE_CONTEXT);
}
}
export { Umb{EntityName}ItemStore as api };
Step 3: Create item server data source
File: {entity}-item.server.data-source.ts
import type { Umb{EntityName}ItemModel } from '../../types.js';
import { UMB_{ENTITY}_ENTITY_TYPE } from '../../entity.js';
import { UmbItemServerDataSourceBase } from '@umbraco-cms/backoffice/repository';
import type { {EntityName}ItemResponseModel } from '@umbraco-cms/backoffice/external/backend-api';
import { {EntityName}Service } from '@umbraco-cms/backoffice/external/backend-api';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
export class Umb{EntityName}ItemServerDataSource extends UmbItemServerDataSourceBase<
{EntityName}ItemResponseModel,
Umb{EntityName}ItemModel
> {
constructor(host: UmbControllerHost) {
super(host, {
: {}.{}({ : { : uniques } }),
: ({
: {}_ENTITY_TYPE,
: item.,
: item. ?? ,
}),
});
}
}
Step 4: Create item repository
File: {entity}-item.repository.ts
import type { Umb{EntityName}ItemModel } from '../../types.js';
import { Umb{EntityName}ItemServerDataSource } from './{entity}-item.server.data-source.js';
import { UMB_{ENTITY}_ITEM_STORE_CONTEXT } from './{entity}-item.store.context-token.js';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import { UmbItemRepositoryBase } from '@umbraco-cms/backoffice/repository';
export class Umb{EntityName}ItemRepository extends UmbItemRepositoryBase<Umb{EntityName}ItemModel> {
constructor(host: UmbControllerHost) {
super(host, Umb{EntityName}ItemServerDataSource, UMB_{ENTITY}_ITEM_STORE_CONTEXT);
}
}
export { Umb{} api };
Step 5: Create constants and manifests
Follow the same pattern as detail (Step 5โ6), using Item instead of Detail in aliases.
Item repository checklist
Option C: Collection Repository
For paginated/filtered listings. No base class โ implement the UmbCollectionRepository interface on UmbRepositoryBase.
Files to create
{package-path}/collection/repository/
โโโ {entity}-collection.repository.ts
โโโ {entity}-collection.server.data-source.ts
โโโ manifests.ts
Step 1: Create collection server data source
File: {entity}-collection.server.data-source.ts
import type { Umb{EntityName}CollectionFilterModel } from '../types.js';
import { {EntityName}Service } from '@umbraco-cms/backoffice/external/backend-api';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import { tryExecute } from '@umbraco-cms/backoffice/resources';
export class Umb{EntityName}CollectionServerDataSource {
#host: UmbControllerHost;
constructor(host: UmbControllerHost) {
this.#host = host;
}
async getCollection(filter: Umb{EntityName}CollectionFilterModel) {
const { data, error } = await tryExecute(
this.#host,
{EntityName}Service.get{EntityName}({ query: { skip: filter.skip, take: filter. } }),
);
(error || !data) {
{ error };
}
{
: {
: data..( ({
})),
: data.,
},
};
}
}
Step 2: Create collection repository
File: {entity}-collection.repository.ts
import { Umb{EntityName}CollectionServerDataSource } from './{entity}-collection.server.data-source.js';
import type { Umb{EntityName}CollectionFilterModel } from '../types.js';
import { UmbRepositoryBase } from '@umbraco-cms/backoffice/repository';
import type { UmbCollectionRepository } from '@umbraco-cms/backoffice/collection';
export class Umb{EntityName}CollectionRepository
extends UmbRepositoryBase
implements UmbCollectionRepository
{
#collectionSource = new Umb{EntityName}CollectionServerDataSource(this);
async requestCollection(filter: Umb{EntityName}CollectionFilterModel) {
return this.#collectionSource.getCollection(filter);
}
}
export { Umb{EntityName}CollectionRepository api };
Collection repository checklist
Option D: Action-Specific Repository
For domain operations that don't fit CRUD โ publish, duplicate, move, sort, recycle bin, etc.
Prerequisites
- Entity type constant
- Generated API client with the relevant endpoint
Files to create
{package-path}/{action-location}/repository/
โโโ {entity}-{action}.repository.ts
โโโ {entity}-{action}.server.data-source.ts
โโโ types.ts # Optional โ args/response types
โโโ manifests.ts
Location rules:
- Entity actions:
entity-actions/{action-name}/repository/
- Bulk actions:
entity-bulk-actions/{action-name}/repository/
- Domain sub-features:
{feature-name}/repository/ (e.g., publishing/repository/)
Step 1: Create types (if needed)
File: types.ts
export interface Umb{Action}{EntityName}RequestArgs {
unique: string;
}
Step 2: Create server data source
File: {entity}-{action}.server.data-source.ts
import type { Umb{Action}{EntityName}RequestArgs } from './types.js';
import { {EntityName}Service } from '@umbraco-cms/backoffice/external/backend-api';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import { tryExecute } from '@umbraco-cms/backoffice/resources';
export class Umb{Action}{EntityName}ServerDataSource {
#host: UmbControllerHost;
constructor(host: UmbControllerHost) {
this.#host = host;
}
async {actionMethod}(args: Umb{Action}{EntityName}RequestArgs) {
if (!args.unique) throw new Error('Unique is missing');
return tryExecute(
this.#host,
{EntityName}Service.{apiMethod}({
: { : args. },
: {
},
}),
);
}
}
Step 3: Create repository
File: {entity}-{action}.repository.ts
import { Umb{Action}{EntityName}ServerDataSource } from './{entity}-{action}.server.data-source.js';
import type { Umb{Action}{EntityName}RequestArgs } from './types.js';
import { UMB_NOTIFICATION_CONTEXT } from '@umbraco-cms/backoffice/notification';
import { UmbRepositoryBase } from '@umbraco-cms/backoffice/repository';
export class Umb{Action}{EntityName}Repository extends UmbRepositoryBase {
#{action}Source = new Umb{Action}{EntityName}ServerDataSource(this);
async request{Action}(args: Umb{Action}{EntityName}RequestArgs) {
const { data, error } = await this.#{action}Source.{actionMethod}(args);
if (!error) {
notificationContext = .();
notification = { : { : } };
notificationContext.(, notification);
}
{ data, error };
}
}
{ {}{} api };
Step 4: Create manifests
File: manifests.ts
export const manifests: Array<UmbExtensionManifest> = [
{
type: 'repository',
alias: 'Umb.Repository.{EntityName}.{Action}',
name: '{EntityName} {Action} Repository',
api: () => import('./{entity}-{action}.repository.js'),
},
];
Action-specific repository checklist
Reference examples
See Repositories โ Reference Examples for real implementations to study.