| name | general-create-package |
| description | Create a new package in the Umbraco backoffice client with its first module. Use when adding a new domain feature area that needs its own package under src/packages/ — e.g., a new CMS feature like data types, tags, or relations. Packages are self-contained domain modules that can theoretically be uninstalled independently. Also use when the user says things like "scaffold a new package", "add a new feature package", or "create a new domain module". |
| allowed-tools | Read, Write, Edit, Grep, Glob |
Create Package
Create a new self-contained package under src/packages/ with its first module.
Foundational documentation
Read these docs before creating a package — they define the conventions this skill builds on:
- Package Development — Package & module structure, folder conventions, manifest bubbling, public API rules
- Entities — Entity types, entity context, how entityType connects workspaces/trees/actions/routing
- Data Flow — Repository pattern, data sources, stores, worked examples
Naming conventions
- Package names are plural (e.g.,
data-types, languages, tags, documents, relations)
- Module names are singular (e.g.,
data-type, language, tag, document, relation)
What you need from the user
- Package name — The domain name in plural form (e.g.,
data-types, languages, tags) — kebab-case
- First module name — The primary module in singular form (e.g.,
data-type, language, tag)
When to create a package vs. add to core
- New package: Domain-specific CMS features (documents, media, data-type, language). Each package is independent and self-contained.
- Add to core: UI framework infrastructure shared by all packages (modals, routing, extension system). Use the
add-core-module skill instead.
Files to create
src/packages/{package-name}/
├── package.json # npm workspace package
├── vite.config.ts # Build configuration
├── umbraco-package.ts # Bundle entry point (lazy-loads manifests)
├── manifests.ts # Aggregates all module manifests
├── {module-name}/ # First module
│ ├── index.ts # Public API exports
│ ├── manifests.ts # Module manifest registrations
│ ├── constants.ts # Module constants
│ └── types.ts # Module types
Step 1: Create package.json
Every package is an npm workspace. It needs a minimal package.json:
{
"name": "@umbraco-backoffice/{package-name}",
"version": "0.0.0",
"private": true,
"type": "module",
"scripts": {
"build": "vite build"
}
}
Step 2: Create vite.config.ts
Non-core packages use the simple default config with three entry points (index.ts, manifests.ts, umbraco-package.ts):
import { defineConfig } from 'vite';
import { rmSync } from 'fs';
import { getDefaultConfig } from '../../vite-config-base';
const dist = '../../../dist-cms/packages/{package-name}';
rmSync(dist, { recursive: true, force: true });
export default defineConfig({
...getDefaultConfig({ dist }),
});
Step 3: Create umbraco-package.ts
The bundle entry point that lazy-loads the package's manifests:
export const name = 'Umbraco.Core.{PackageName}';
export const extensions = [
{
name: '{PackageName} Bundle',
alias: 'Umb.Bundle.{PackageName}',
type: 'bundle',
js: () => import('./manifests.js'),
},
];
Convention: name uses Umbraco.Core.{PascalCaseName}, alias uses Umb.Bundle.{PascalCaseName}.
Step 4: Create the package-level manifests.ts
Aggregates all module manifests:
import { manifests as {moduleName}Manifests } from './{module-name}/manifests.js';
export const manifests: Array<UmbExtensionManifest> = [
...{moduleName}Manifests,
];
As you add more modules, import and spread their manifests here.
Step 5: Create the first module
{module-name}/manifests.ts
export const manifests: Array<UmbExtensionManifest> = [
];
{module-name}/index.ts
{module-name}/constants.ts
{module-name}/types.ts
Step 6: Register the package
Three registrations are needed to wire the package into the build:
1. Add subpath export to root package.json
In /src/Umbraco.Web.UI.Client/package.json, add to the exports field:
"./{package-name}": "./dist-cms/packages/{package-name}/index.js"
2. Regenerate TypeScript config
npm run generate:tsconfig
This updates tsconfig.json paths so @umbraco-cms/backoffice/{package-name} resolves correctly.
3. Install workspace dependencies
npm install
This registers the new workspace package with npm.
Reference: existing packages to study
- Simple package:
src/packages/data-type/ — straightforward entity with CRUD
- Complex package:
src/packages/documents/ — multiple modules, rich entity
- Minimal package:
src/packages/tags/ — small feature area
Checklist