29 KiB
Umbraco CMS - Multi-Project Repository
Enterprise-grade CMS built on .NET 10.0. This repository contains 21 production projects organized in a layered architecture with clear separation of concerns.
Repository: https://github.com/umbraco/Umbraco-CMS
License: MIT
Main Branch: main
1. Overview
What This Repository Contains
21 Production Projects organized in 3 main categories:
-
Core Architecture (Domain & Infrastructure)
Umbraco.Core- Interface contracts, domain models, notificationsUmbraco.Infrastructure- Service implementations, data access, caching
-
Web & APIs (Presentation Layer)
Umbraco.Web.UI- Main ASP.NET Core web applicationUmbraco.Web.Common- Shared web functionality, controllers, middlewareUmbraco.Cms.Api.Management- Backoffice Management API (REST)Umbraco.Cms.Api.Delivery- Content Delivery API (headless)Umbraco.Cms.Api.Common- Shared API infrastructure
-
Specialized Features (Pluggable Modules)
- Persistence: EF Core (modern), NPoco (legacy) for SQL Server & SQLite
- Caching:
PublishedCache.HybridCache(in-memory + distributed) - Search:
Examine.Lucene(full-text search) - Imaging:
Imaging.ImageSharpv1 & v2 (image processing) - Other: Static assets, targets, development tools
6 Test Projects:
Umbraco.Tests.Common- Shared test utilitiesUmbraco.Tests.UnitTests- Unit testsUmbraco.Tests.Integration- Integration testsUmbraco.Tests.Benchmarks- Performance benchmarksUmbraco.Tests.AcceptanceTest- E2E testsUmbraco.Tests.AcceptanceTest.UmbracoProject- Test instance
Key Technologies
- .NET 10.0 - Target framework for all projects
- ASP.NET Core - Web framework
- Entity Framework Core - Modern ORM
- OpenIddict - OAuth 2.0/OpenID Connect authentication
- Microsoft.AspNetCore.OpenApi - OpenAPI document generation
- Swashbuckle.AspNetCore.SwaggerUI - Swagger UI for API documentation
- Lucene.NET - Full-text search via Examine
- ImageSharp - Image processing
2. Repository Structure
Umbraco-CMS/
├── src/ # 21 production projects
│ ├── Umbraco.Core/ # Domain contracts (interfaces only)
│ │ └── CLAUDE.md # ⭐ Core architecture guide
│ ├── Umbraco.Infrastructure/ # Service implementations
│ ├── Umbraco.Web.Common/ # Web utilities
│ ├── Umbraco.Web.UI/ # Main web application
│ ├── Umbraco.Cms.Api.Management/ # Management API
│ ├── Umbraco.Cms.Api.Delivery/ # Delivery API (headless)
│ ├── Umbraco.Cms.Api.Common/ # Shared API infrastructure
│ │ └── CLAUDE.md # ⭐ API patterns guide
│ ├── Umbraco.PublishedCache.HybridCache/ # Content caching
│ ├── Umbraco.Examine.Lucene/ # Search indexing
│ ├── Umbraco.Cms.Persistence.EFCore/ # EF Core data access
│ ├── Umbraco.Cms.Persistence.EFCore.Sqlite/
│ ├── Umbraco.Cms.Persistence.EFCore.SqlServer/
│ ├── Umbraco.Cms.Persistence.Sqlite/ # Legacy SQLite
│ ├── Umbraco.Cms.Persistence.SqlServer/ # Legacy SQL Server
│ ├── Umbraco.Cms.Imaging.ImageSharp/ # Image processing v1
│ ├── Umbraco.Cms.Imaging.ImageSharp2/ # Image processing v2
│ ├── Umbraco.Cms.StaticAssets/ # Embedded assets
│ ├── Umbraco.Cms.DevelopmentMode.Backoffice/
│ ├── Umbraco.Cms.Targets/ # NuGet targets
│ └── Umbraco.Cms/ # Meta-package
│
├── tests/ # 6 test projects
│ ├── Umbraco.Tests.Common/
│ ├── Umbraco.Tests.UnitTests/
│ ├── Umbraco.Tests.Integration/
│ ├── Umbraco.Tests.Benchmarks/
│ ├── Umbraco.Tests.AcceptanceTest/
│ └── Umbraco.Tests.AcceptanceTest.UmbracoProject/
│
├── templates/ # Project templates
│ └── Umbraco.Templates/
│
├── tools/ # Build tools
│ └── Umbraco.JsonSchema/
│
├── umbraco.sln # Main solution file
├── Directory.Build.props # Shared build configuration
├── Directory.Packages.props # Centralized package versions
├── .editorconfig # Code style
└── .globalconfig # Roslyn analyzers
Architecture Layers
Dependency Flow (unidirectional, always flows inward):
Web.UI → Web.Common → Infrastructure → Core
↓
Api.Management → Api.Common → Infrastructure → Core
↓
Api.Delivery → Api.Common → Infrastructure → Core
Key Principle: Core has NO dependencies (pure contracts). Infrastructure implements Core. Web/APIs depend on Infrastructure.
Project Dependencies
Core Layer:
Umbraco.Core→ No dependencies (only Microsoft.Extensions.*)
Infrastructure Layer:
Umbraco.Infrastructure→Umbraco.CoreUmbraco.PublishedCache.*→Umbraco.InfrastructureUmbraco.Examine.Lucene→Umbraco.InfrastructureUmbraco.Cms.Persistence.*→Umbraco.Infrastructure
Web Layer:
Umbraco.Web.Common→Umbraco.Infrastructure+ caching + searchUmbraco.Web.UI→Umbraco.Web.Common+ all features
API Layer:
Umbraco.Cms.Api.Common→Umbraco.Web.CommonUmbraco.Cms.Api.Management→Umbraco.Cms.Api.CommonUmbraco.Cms.Api.Delivery→Umbraco.Cms.Api.Common
3. Teamwork & Collaboration
Branching Strategy
- Main branch:
main(protected) - Branch naming convention:
v<version>/<type>/<description>
Format: v{major-version}/{type}/{kebab-case-description}
Version: Read from version.json in the repository root. Use the major version number (e.g., v17 for version 17.x.x).
Types:
| Type | Use Case |
|---|---|
feature |
New feature being introduced to the product |
bugfix |
Fix to an existing issue with the product |
qa |
Adding or updating unit, integration, or end-to-end tests |
improvement |
Update to something that already exists but isn't broken (UI finessing, refactoring) |
task |
Update that doesn't directly impact product behavior (dependency updates, build pipeline) |
Description: A short, kebab-case description (a few words). This should be prefixed with the GitHub issue number if the update is related to resolving a tracked issue.
Examples:
v17/bugfix/12345-correct-display-of-pending-migrations
v17/feature/add-webhook-support
v17/improvement/optimize-content-cache
v17/qa/add-media-service-tests
v17/task/update-ef-core-dependency
See .github/CONTRIBUTING.md for full guidelines.
Pull Request Process
- PR Template:
.github/pull_request_template.md - Required CI Checks:
- All tests pass
- Code formatting (dotnet format)
- No build warnings
- Merge Strategy: Squash and merge (via GitHub UI)
- Reviews: Required from code owners
PR Naming Convention
Use the format: Area: Description (closes #IssueID)
Examples:
| Area | Description | Issue |
|---|---|---|
| Relations: | Move persistence of relations from repository into notification handlers | (closes #00000) |
| Management API: | Correct the population of the parent for sibling items when retrieved under a folder | |
| Docs: | Updated contributing guidelines to welcome contributions on bugfixes |
Area: The feature or aspect affected (e.g., UFM, TipTap, Docs, Segmentation, Migrations). Helps readers quickly understand what is being changed.
Description Best Practices:
- Include the area of change (Relations, Management API, etc.)
- Describe the change and its impact
- Be specific, not vague (describe "a golden retriever" not just "a dog")
Issue Linking: Add (closes #IssueID) to the title for readability, AND include a closing keyword on its own line in the PR body (e.g., Fixes #IssueID) so GitHub actually auto-links and auto-closes the issue on merge. GitHub only parses closing keywords (closes, fixes, resolves) from the PR body or commit messages — the title suffix is cosmetic and does not trigger auto-close on its own.
Commit Messages
Follow Conventional Commits format:
<type>(<scope>): <description>
Types: feat, fix, docs, style, refactor, test, chore
Scope: project name (core, web, api, etc.)
Examples:
feat(core): add IContentService.GetByIds method
fix(api): resolve null reference in schema handler
docs(web): update routing documentation
Code Owners
Project ownership is distributed across teams. Check individual project directories for ownership.
4. Architecture Patterns
Core Architectural Decisions
-
Layered Architecture with Dependency Inversion
- Core defines contracts (interfaces)
- Infrastructure implements contracts that need Infrastructure-owned machinery
- Web/APIs consume implementations via DI
Where service implementations live: Services whose dependencies are satisfiable from Core interfaces alone (repositories, scope, config, other Core services) live in
Umbraco.Core/Services/— this covers the majority of domain services (MemberService,ContentService,MediaService,ContentTypeService,EntityService,AuditService,ExternalMemberService, etc.). Service implementations only live inUmbraco.Infrastructure/Services/Implement/when they genuinely need Infrastructure concerns — Examine indexes (ContentSearchService,MediaSearchService,IndexedEntitySearchService), log files (LogViewerRepository), packaging internals (PackagingService), webhook firing (WebhookFiringService), distributed-job coordination (DistributedJobService). When adding a new service, default to Core and only move to Infrastructure if a concrete dependency forces it. -
Interface-First Design
- All services defined as interfaces in Core
- Enables testing, polymorphism, extensibility
-
Notification Pattern (not C# events)
- See
/src/Umbraco.Core/CLAUDE.md→ "2. Notification System (Event Handling)"
- See
-
Composer Pattern (DI registration)
- See
/src/Umbraco.Core/CLAUDE.md→ "3. Composer Pattern (DI Registration)"
- See
-
Scoping Pattern (Unit of Work)
- See
/src/Umbraco.Core/CLAUDE.md→ "5. Scoping Pattern (Unit of Work)"
- See
-
Attempt Pattern (operation results)
Attempt<TResult, TStatus>instead of exceptions- Strongly-typed operation status enums
Key Design Patterns Used
- Repository Pattern - Data access abstraction
- Unit of Work - Scoping for transactions
- Builder Pattern -
ProblemDetailsBuilderfor API errors - Strategy Pattern - OpenAPI handlers (schema ID, operation ID)
- Options Pattern - All configuration via
IOptions<T> - Factory Pattern - Content type factories
- Mediator Pattern - Notification aggregator
5. Avoiding Breaking Changes
No binary breaking changes are allowed within a major version. Three patterns are used:
5.1 Obsolete Constructor + StaticServiceProvider
When a public class needs new dependencies, obsolete the existing constructor and add a new one. The old constructor delegates to the new one, resolving missing deps via StaticServiceProvider.
[Obsolete("Please use the constructor with all parameters. Scheduled for removal in Umbraco 19.")]
public MyService(IDependencyA depA)
: this(
depA,
StaticServiceProvider.Instance.GetRequiredService<IDependencyB>())
{
}
public MyService(IDependencyA depA, IDependencyB depB)
{
_depA = depA;
_depB = depB;
}
Examples:
ContentCollectionPresentationFactory- addedFlagProviderCollectionCacheInstructionService- addedILastSyncedManager,IRepositoryCacheVersionServiceDocumentPresentationFactory- addedFlagProviderCollection
Rules:
- Old constructor marked
[Obsolete("... Scheduled for removal in Umbraco {current-major+2}.")] - Old constructor calls new constructor via
: this(...) - Uses
StaticServiceProvider.Instance.GetRequiredService<T>()for new params only - DI registration must use the NEW constructor (old is for external consumers only)
5.2 Obsolete Method + New Overload
When a public method signature needs to change, add the new method/overload and obsolete the old. The obsolete method should call the new one with suitable defaults.
[Obsolete("Use the overload taking all parameters. Scheduled for removal in Umbraco 19.")]
public void DoThing(string name)
=> DoThing(name, extraParam: null);
public void DoThing(string name, string? extraParam)
{
// Real implementation here
}
Rules:
- Old method marked
[Obsolete]with removal schedule - DRY: old method calls new method, providing defaults for new parameters
- All internal callers must be updated to use the new method
- No callers should remain on the obsolete method within the codebase
5.3 Default Interface Implementation
When adding methods to a public interface, provide a default implementation so existing external implementations don't break.
public interface IMyService
{
// Existing method
void ExistingMethod();
// New method with default implementation
void NewMethod(string param)
=> ExistingMethod(); // delegate to existing if possible
}
Strategies for the default (in order of preference):
- Use existing interface methods to satisfy the contract (even if not optimal)
- Return a sensible default like empty collection, null, etc.
- Throw
NotImplementedExceptionif no reasonable default exists
Example: IContentService.SaveBlueprint - new overload with IContent? createdFromContent has a default impl that calls the old method (ignoring the new param).
Example: IDocumentPresentationFactory.CreateCulturePublishScheduleModels - full default implementation with logic, uses StaticServiceProvider for dependency resolution within the interface.
Rules:
- Add
// TODO (V{next-major}): Remove the default implementation when {obsolete method} is removed.comment - Default impl should be functionally correct even if not optimal
- If using
StaticServiceProviderin a default impl, note this is temporary
5.4 General Rules
- Removal policy: Obsoleted members must remain for at least one full major version before removal. If obsoleted in version N, the earliest removal is version N+2. For example, something obsoleted in v17 is scheduled for removal in v19 (giving the whole of v18 as a deprecation period).
- All
[Obsolete]attributes must include "Scheduled for removal in Umbraco {current+2}" - Read
version.jsonto determine the current major version - Suppress
CS0618warnings where obsolete members must call each other:#pragma warning disable CS0618 // Type or member is obsolete => OldMethod(param); #pragma warning restore CS0618 // Type or member is obsolete - Update ALL internal callers to use the new API - no internal code should use obsolete members
6. Project-Specific Notes
Centralized Package Management
NuGet package versions are centralized in Directory.Packages.props. There are two Directory.Packages.props files in the source tree, with multi-level merging enabled so the test file inherits from the root:
| File | Scope |
|---|---|
Directory.Packages.props (root) |
Production source code packages — referenced by all src/** projects |
tests/Directory.Packages.props |
Test-only packages (NUnit, Moq, Bogus, BenchmarkDotNet, etc.) — adds entries on top of the inherited root file |
When updating dependencies, decide which file the package belongs in:
- A package used only by test projects →
tests/Directory.Packages.props - A package used by any production project (or by both production and tests) → root
Directory.Packages.props
<!-- Individual projects reference WITHOUT version -->
<PackageReference Include="Microsoft.AspNetCore.OpenApi" />
<!-- Versions defined in Directory.Packages.props -->
<PackageVersion Include="Microsoft.AspNetCore.OpenApi" Version="10.0.0" />
Opt-out: src/Umbraco.Web.UI/Umbraco.Web.UI.csproj sets <ManagePackageVersionsCentrally>false</ManagePackageVersionsCentrally> and specifies versions inline (for Microsoft.EntityFrameworkCore.Design, Microsoft.Build.Tasks.Core, Microsoft.ICU.ICU4C.Runtime, etc.). Update those versions directly in that csproj when bumping. Two further Directory.Packages.props files exist under templates/ for the project/extension templates and have their own version sets — keep Microsoft.AspNetCore.OpenApi aligned between the root file and templates/UmbracoExtension/.
Build Configuration
Directory.Build.props- Shared properties (target framework, company, copyright).editorconfig- Code style rules.globalconfig- Roslyn analyzer rules
Persistence Layer - NPoco and EF Core
The repository contains BOTH (actively supported):
- Current: NPoco-based persistence (
Umbraco.Cms.Persistence.Sqlite,Umbraco.Cms.Persistence.SqlServer) - widely used and fully supported - Future: EF Core-based persistence (
Umbraco.Cms.Persistence.EFCore.*) - migration in progress
Note: The codebase is actively migrating to EF Core, but NPoco remains the primary persistence layer and is not deprecated. Both are fully supported.
Authentication: OpenIddict
All APIs use OpenIddict (OAuth 2.0/OpenID Connect):
- Reference tokens (not JWT) for better security
- Secure cookie-based token storage (v17+) - tokens stored in HTTP-only cookies with
__Host-prefix - Tokens are redacted from client-side responses and passed via secure cookies only (
[redacted]placeholder) - ASP.NET Core Data Protection for token encryption
- Configured in
Umbraco.Cms.Api.Common - API requests must include credentials (
credentials: includefor fetch)
Load Balancing Requirement: All servers must share the same Data Protection key ring.
Frontend auth pitfalls — see src/Umbraco.Web.UI.Client/docs/edge-cases.md (Auth & Cross-tab section) and docs/security.md. Key points:
- Never call
validateToken()per API request — it revokes the previous reference token (ID2019 errors) window.openeris set for ANYwindow.open()target, not only OAuth popups — scope guards to the pathname too- BroadcastChannel does not deliver messages to the sender's own tab
Content Caching Strategy
HybridCache (Umbraco.PublishedCache.HybridCache):
- In-memory cache + distributed cache support
- Published content only (not draft)
- Invalidated via notifications and cache refreshers
API Versioning
APIs use Asp.Versioning.Mvc:
- Management API:
/umbraco/management/api/v{version}/* - Delivery API:
/umbraco/delivery/api/v{version}/* - OpenAPI docs:
/umbraco/openapi/management.json,/umbraco/openapi/delivery.json - Swagger UI:
/umbraco/openapi/
Updating OpenApi.json (Management API)
When a PR changes Management API controllers or models, the OpenApi.json file in the Management API project must be updated:
- Run the Umbraco instance locally
- Open Swagger UI and navigate to the swagger.json link (e.g.
https://localhost:44339/umbraco/swagger/management/swagger.json) - Copy the full JSON content and paste it into
src/Umbraco.Cms.Api.Management/OpenApi.json
Important: Commit only the substantive changes — not IDE-applied formatting (whitespace, reordering, etc.). Extraneous formatting diffs make PRs harder to review and merge-ups more error-prone.
Backoffice npm Package
The backoffice is published to npm as @umbraco-cms/backoffice. Runtime dependencies are provided via importmap; npm peerDependencies provide types only. For full details on dependency hoisting, version range logic, and plugin development, see /src/Umbraco.Web.UI.Client/CLAUDE.md → "npm Package Publishing".
SQL Server 2100-parameter limit
Any WHERE IN (@0, @1, ...) built from a runtime-sized collection risks hitting SQL Server's 2100-parameter ceiling and throwing SqlException 8003 in production.
Batch with IEnumerable<T>.InGroupsOf(Constants.Sql.MaxParameterCount) or Database.FetchByGroups(...) whenever the collection size is driven by user data — not just when it currently fits. Watch for products of two scaling dimensions (documents × languages, properties × versions) and config-tunable batch sizes whose defaults are safe but ceilings aren't.
Full guidance, safe patterns and decision rule: see /src/Umbraco.Infrastructure/CLAUDE.md → "Avoiding the SQL Server 2100-parameter limit".
Known Limitations
- Circular Dependencies: Avoided via
Lazy<T>or event notifications - Multi-Server: Requires shared Data Protection key ring and synchronized clocks (NTP)
- Database Support: SQL Server, SQLite
7. CI/CD — Claude AI Assistant
Two GitHub Actions workflows powered by anthropics/claude-code-action@v1. Advisory only — does not block merging.
Workflows
| File | Trigger | Purpose |
|---|---|---|
claude-review.yml |
pull_request: [opened, ready_for_review] |
Auto-review every non-draft PR using the umb-review skill |
claude.yml |
@claude comments, issue assign/label |
Interactive assistant for PRs and issues |
Auto-Review (claude-review.yml)
Runs the full .claude/skills/umb-review/SKILL.md procedure on every newly opened or un-drafted PR. Produces inline comments per finding and one summary comment with a verdict. Skips draft PRs. No turn limit.
Interactive (claude.yml)
Responds to @claude mentions on PRs and issues. The trigger phrase is stripped before Claude sees the message, so:
@claude review→ light review usinggh pr diff(not the umb-review skill)@claude fix ...→ implements a fix on a new branch@claude help→ answers questions about the codebase@claude label→ applies labels@claude(empty) → defaults toreviewon PRs,helpon issues
Also triggers on issue assignment to claude or adding the claude label. Gated: only runs when @claude appears in the comment/issue body. Max 25 turns.
Allowed Bash tools: gh, git, npm, dotnet (interactive only; auto-review allows gh and git).
Labels
Both workflows apply labels based on content:
On PRs (based on changed files):
| Label | Condition |
|---|---|
area/frontend |
Files under src/Umbraco.Web.UI.Client/ |
area/backend |
.cs files outside the frontend client |
area/test |
Only test files changed |
category/api |
Management or Delivery API files |
category/breaking |
Breaking changes detected |
category/localization |
Localization/language files |
category/test-automation |
Only test files changed |
category/refactor |
Pure refactoring, no new features |
category/performance |
Performance-related changes |
category/ux |
User-facing changes |
category/ui |
UI layer changes |
On Issues (based on content): same area/* and category/* labels, plus affected/v14 through affected/v17 and affected/backoffice.
Labels are only added, never removed. Claude applies only labels it is confident about.
Key Implementation Notes
- Checkout required — the action internally runs
git fetch origin mainfor trusted file restoration. Withoutactions/checkout, it fails withfatal: not a git repository. id-token: writepermission — required for OIDC token exchange with the Claude GitHub App.- Trigger phrase stripping — the action strips
@claudefrom comments before passing to Claude. Prompts must reference commands without the prefix (e.g.,reviewnot@claude review). - PR number injection — the interactive workflow injects the PR/issue number into the prompt via
${{ github.event.issue.number }}since Claude can't discover it fromgh pr viewwhen checked out onmain.
8. Code Comment Policy
Default to no comment. Applies to all code in this repository — C#, TypeScript, Razor, build scripts. Well-named identifiers and small functions are the primary form of self-documentation; comments are a fallback for the rare cases where the code itself cannot carry the meaning.
When NOT to comment
- Don't restate what the code does. A line calling
resetState()does not need// Reset state. A method namedvalidateInputdoes not need// Validate input. - Don't narrate a sequence of calls. If three lines run in order, the order is in the code — don't paraphrase it above.
- Don't reference the current task, fix, callers, or PR. No
// Fix for X,// Used by Y,// Added for the Z flow,// See PR #1234. That belongs in commit messages and PR descriptions; in source it rots as the codebase evolves.
When a comment IS justified
Write a comment only when removing it would leave a future reader confused. Concretely:
- A non-obvious WHY. A hidden constraint, business rule, or ordering requirement that is not visible from the code.
- A workaround for a specific bug or platform quirk. Link the issue (
(#21996),https://...) so the comment can be deleted once the upstream fix lands. - A subtle invariant that the type system or method names do not enforce.
- An edge case the code intentionally handles that would surprise a reader (e.g. "must run before X because Y").
- API documentation — XML doc comments on C# members, JSDoc on exported TypeScript symbols. Required for the public contract; still keep them concise.
TODOs
Allowed, but cheap to write and cheaper to leave behind. Keep them short and trackable: // TODO (V19): remove once obsolete overload is gone or // TODO: pagination [NL]. A TODO should have an author or a version trigger.
9. Testing Practices
Tests for a bug fix must fail before the fix
Verify any test you add for a bug fix actually catches the bug: either write the failing test first (TDD), or temporarily revert the production change and confirm the test fails before re-applying. A test that passes both ways proves nothing. Watch for coincidental passes — default seed/sort orders can make a buggy path produce the right answer for the test's specific inputs; construct inputs so the broken and fixed behaviours give visibly different results.
For integration tests that exercise caching or cache refreshers, see tests/Umbraco.Tests.Integration/CLAUDE.md — the harness disables caching by default, which can produce false greens.
Quick Reference
Essential Commands
# Build solution
dotnet build
# Run all tests
dotnet test
# Run specific test category
dotnet test --filter "Category=Integration"
# Format code
dotnet format
# Pack all projects
dotnet pack -c Release
Integration Test Database Configuration
Integration tests are configured in tests/Umbraco.Tests.Integration/appsettings.Tests.json.
The Tests:Database:DatabaseType setting controls which database is used:
"SQLite"(default) - No external dependencies"LocalDb"- Uses SQL Server LocalDB, required for SQL Server-specific tests (e.g., page-level locking,sys.dm_tran_locks)
SQL Server-specific tests use BaseTestDatabase.IsSqlite() to skip when running on SQLite.
Key Projects
| Project | Type | Description |
|---|---|---|
| Umbraco.Core | Library | Interface contracts and domain models |
| Umbraco.Infrastructure | Library | Service implementations and data access |
| Umbraco.Web.UI | Application | Main web application (Razor/MVC) |
| Umbraco.Cms.Api.Management | Library | Management API (backoffice) |
| Umbraco.Cms.Api.Delivery | Library | Delivery API (headless CMS) |
| Umbraco.Cms.Api.Common | Library | Shared API infrastructure |
| Umbraco.PublishedCache.HybridCache | Library | Published content caching |
| Umbraco.Examine.Lucene | Library | Full-text search indexing |
Important Files
- Solution:
umbraco.sln - Build Config:
Directory.Build.props,Directory.Packages.props - Code Style:
.editorconfig,.globalconfig - Documentation:
/CLAUDE.md,/src/Umbraco.Core/CLAUDE.md,/src/Umbraco.Cms.Api.Common/CLAUDE.md
Project-Specific Documentation
For detailed information about individual projects, see their CLAUDE.md files:
- Core Architecture:
/src/Umbraco.Core/CLAUDE.md- Service contracts, notification patterns - API Infrastructure:
/src/Umbraco.Cms.Api.Common/CLAUDE.md- OpenAPI, authentication, serialization - Backoffice Frontend:
/src/Umbraco.Web.UI.Client/CLAUDE.md- Lit web components, extension system, auth client
Important: When working on backoffice client code (anything under src/Umbraco.Web.UI.Client/), read /src/Umbraco.Web.UI.Client/CLAUDE.md first. It contains action-specific checklists (deprecation, testing, security, etc.) that are not duplicated here.
Getting Help
- Official Docs: https://docs.umbraco.com/
- Contributing Guide:
.github/CONTRIBUTING.md - Issues: https://github.com/umbraco/Umbraco-CMS/issues
- Community: https://forum.umbraco.com/
- Releases: https://releases.umbraco.com/
This repository follows a layered architecture with strict dependency rules. The Core defines contracts, Infrastructure implements them, and Web/APIs consume them. Each layer can be understood independently, but dependencies always flow inward toward Core.