DoubleSync.Umbraco 17.0.1-alpha.0.9
DoubleSync for Umbraco
Sync schema, content, media, and people between Umbraco environments — directly from the backoffice. DoubleSync is an Umbraco v17+ backoffice package with a merge editor, SyncPacks, RBAC, audit trail, and more.
Free Community tier includes schema sync and diff preview. Pro and Agency tiers unlock full content, media, and people sync with conflict resolution.
Table of Contents
- Features
- Requirements
- Installation
- Quick Start
- Backoffice Dashboard
- Architecture
- Developer Guide
- Troubleshooting
- License
Features
| Feature | Community | Pro | Agency |
|---|---|---|---|
| Schema sync (data types + document types) | Yes | Yes | Yes |
| Content sync (documents with variants) | — | Yes | Yes |
| Media sync (folders + binary blobs) | — | Yes | Yes |
| People sync (users, groups, members) | — | Yes | Yes |
| Diff / status preview | Yes | Yes | Yes |
| Merge editor (per-property conflict resolution) | — | Yes | Yes |
| SyncPack (portable ZIP packages) | — | Yes | Yes |
| Culture-specific sync | — | Yes | Yes |
| Node-level push/pull with dependency resolution | — | Yes | Yes |
| RBAC (per-user-group, per-environment) | — | Yes | Yes |
| Audit trail with user attribution | — | Yes | Yes |
| Restore points (auto-archive before sync) | — | Yes | Yes |
| Delete detection | — | Yes | Yes |
| Scheduled auto-snapshots | — | — | Yes |
| Azure Blob Storage transport | — | — | Yes |
| Unlimited domains | — | — | Yes |
Requirements
- .NET 10 (or later)
- Umbraco v17+
- An API User on each remote Umbraco instance (see Quick Start)
Installation
dotnet add package DoubleSync.Umbraco
For Azure Blob Storage support (Agency license):
dotnet add package DoubleSync.Storage.Azure
Restart Umbraco. The DoubleSync section appears in the backoffice.
Quick Start
1. Create an API User
On every remote Umbraco instance you want to sync with, create an API User:
Option A — Via appsettings.json (recommended for automation):
{
"Umbraco": {
"CMS": {
"Security": {
"BackOfficeApiClients": {
"doublesync": {
"ClientId": "umbraco-back-office-doublesync",
"ClientSecret": "your-secret-here",
"AllowedGrantTypes": ["client_credentials"],
"AllowedScopes": ["All"]
}
}
}
}
}
}
Option B — Via the Umbraco Backoffice:
- Go to Settings → Users → API Users.
- Click Create API User.
- Name it (e.g.
doublesync). The Client ID will beumbraco-back-office-doublesync. - Copy the Client Secret shown.
- Assign Content and Settings section permissions.
2. Install & Initialise the CLI
dotnet tool install --global DoubleSync.Cli --add-source https://nuget.double.pt/nuget
doublesync init
This creates a .doublesync/ directory with configuration and snapshot storage.
3. Configure Environments
# Configure source (e.g. DEV)
doublesync config set-source \
--url https://dev.example.com \
--client-id umbraco-back-office-doublesync \
--client-secret your-dev-secret
# Configure target (e.g. UAT)
doublesync config set-target \
--url https://uat.example.com \
--client-id umbraco-back-office-doublesync \
--client-secret your-uat-secret
# Verify
doublesync config show
4. Sync!
# Pull everything from DEV
doublesync pull --include-content --include-media
# Preview what would change on UAT
doublesync push --dry-run
# Push to UAT
doublesync push --include-content --include-media
# Check differences
doublesync status
Umbraco Backoffice Dashboard
When the DoubleSync.Umbraco NuGet package is installed, a DoubleSync dashboard appears in the Content section with two tabs:
Sync Tab
- Add Environment — Register remote Umbraco instances with name, URL, Client ID, and Client Secret.
- 🔌 Test — Verify connectivity and authentication.
- ⬇ Pull — Export from the remote instance and import into this one.
- ⬆ Push — Export from this instance and import into the remote one.
- 📊 Status — Compare and show a diff summary without applying changes.
- 🗑 Delete — Remove a configured environment.
- Sync Options — Toggle whether to include Content and/or Media (schema is always synced).
- Last Result — Summary of the most recent sync operation with counts and error details.
- Sync History — Table of the last 10 sync operations with timestamps and results.
Documentation Tab
Built-in reference documentation covering:
- Getting started guide
- Dashboard action reference
- Sync option descriptions
- CLI usage examples
- Filtering & conflict resolution flags
- API User setup instructions
- Architecture overview
- Troubleshooting tips
CLI Command Reference
Initialisation & Configuration
doublesync init # Create .doublesync/ config directory
doublesync config set-source --url ... --client-id ... --client-secret ...
doublesync config set-target --url ... --client-id ... --client-secret ...
doublesync config show # Display current configuration
doublesync test-connection --url ... --client-id ... --client-secret ...
Schema Sync
# Export all schema (data types + document types)
doublesync schema-export
# Export only data types or document types
doublesync schema-export --type datatypes
doublesync schema-export --type doctypes
# Import schema (with optional dry-run)
doublesync schema-import
doublesync schema-import --dry-run
# Compare schema between snapshot and target
doublesync schema-diff
Content Sync
# Export all content
doublesync content-export
# Export a specific branch or culture
doublesync content-export --path /home
doublesync content-export --culture en-US
# Import content (with optional dry-run)
doublesync content-import
doublesync content-import --dry-run
# Compare content
doublesync content-diff
Media Sync
doublesync media-export
doublesync media-import
doublesync media-import --dry-run
doublesync media-diff
Bidirectional Sync (Push / Pull)
# Pull from remote → local snapshot → import here
doublesync pull
doublesync pull --include-content --include-media
# Push from here → export → import to remote
doublesync push
doublesync push --include-content --include-media
doublesync push --schema-only
# Preview changes
doublesync push --dry-run
doublesync pull --dry-run
# Check what changed since last sync
doublesync status
Filtering Options
| Flag | Example | Description |
|---|---|---|
--type |
--type datatype |
Filter by item type: datatype, doctype, content, media |
--path |
--path "/Home/About" |
Filter by content tree path |
--culture |
--culture en-US |
Filter by culture (variant content) |
--dry-run |
schema-import --dry-run |
Preview changes without applying |
--interactive |
push --interactive |
Prompt before each change |
--strategy |
push --strategy source-wins |
Conflict resolution strategy |
Conflict Resolution
When items have been modified on both source and target since the last sync:
| Strategy | Behaviour |
|---|---|
source-wins |
Source version overwrites target |
target-wins |
Target version is kept, source changes discarded |
skip |
Conflicting items are skipped entirely |
doublesync push --strategy source-wins
doublesync push --strategy target-wins
doublesync push --strategy skip
doublesync push --interactive # Choose per-item
Architecture
Project Structure
DoubleSync/
├── src/
│ ├── DoubleSync.Core/ # Core library
│ │ ├── ApiClient/ # Umbraco Management API HTTP client + OAuth2
│ │ ├── Config/ # Configuration management
│ │ ├── Diff/ # Diff engine (schema, content, media)
│ │ ├── Export/ # Exporters (schema, content, media)
│ │ ├── Import/ # Importers (schema, content, media)
│ │ ├── Models/ # API + snapshot data models
│ │ ├── Snapshot/ # JSON snapshot reader / writer
│ │ └── Sync/ # Bidirectional orchestrator + manifest
│ ├── DoubleSync.Cli/ # CLI tool (System.CommandLine)
│ │ └── Program.cs # All CLI commands and argument parsing
│ └── DoubleSync.Umbraco/ # Umbraco backoffice package (Razor Class Library)
│ ├── Client/ # Frontend (Lit + TypeScript + Vite)
│ │ ├── src/
│ │ │ ├── api/ # API client for backend endpoints
│ │ │ ├── dashboard/ # Dashboard Lit web component
│ │ │ └── index.ts # Entry point
│ │ ├── public/
│ │ │ └── umbraco-package.json # Extension manifest
│ │ ├── package.json
│ │ ├── vite.config.ts
│ │ └── tsconfig.json
│ ├── Composers/ # Umbraco startup composer (Swagger config)
│ ├── Controllers/ # Management API controller
│ ├── Services/ # Backend sync service
│ └── wwwroot/ # Built frontend assets
├── tests/
│ ├── DoubleSync.Core.Tests/ # 91+ unit tests (xUnit)
│ └── DoubleSync.Integration.Tests/ # Integration tests against live instances
├── demo-instances/
│ ├── dev/ # DEV Umbraco instance (port 44311)
│ └── uat/ # UAT Umbraco instance (port 44312)
├── start-demo.ps1 # Script to launch both demo instances
└── DoubleSync.sln
NuGet Packages
| Package | Type | Description |
|---|---|---|
DoubleSync.Core |
Class Library | API client, exporters, importers, diff engine, sync orchestrator |
DoubleSync.Umbraco |
Razor Class Library | Umbraco backoffice package with Lit web components |
DoubleSync.Storage.Azure |
Class Library | Azure Blob Storage provider for snapshots and media |
Published to NuGet.org.
How It Works
- Export — Reads data types, document types, content, and media from an Umbraco instance via the Management API. Saves as human-readable JSON snapshots.
- Diff — Compares snapshots against a target instance. Uses GUID-first matching with name/alias fallback.
- Import — Creates/updates items on the target in dependency order (folders → data types → element types → document types → content → media).
- Sync Manifest — Tracks the last sync state to detect conflicts on subsequent operations.
- Publish State — Captures and restores per-culture publish state for content documents.
Developer Guide
Internal references (team)
- Test environments matrix — every demo / QA host on OVH, which tier it runs, DB names, license setup, bring-up commands.
- NuGet publishing — private vs public feed, queue-time toggle for nuget.org pushes, obfuscation, source protection.
- Licensing policy — Ed25519 signing, domain binding, LTS-to-LTS upgrade model, renewal flow.
- Multi-developer workflow — concurrency primitives (per-env lock, staleness watermark, dirty-bit pull guard).
- Project status — current sprint, open work.
Prerequisites
- .NET 10.0 SDK
- Node.js 18+ (for frontend development)
- Git
Building
# Build everything
dotnet build
# Build release
dotnet build -c Release
Running Tests
# Run all unit tests (91+ tests)
dotnet test
# Run with verbose output
dotnet test --verbosity normal
# Run specific test project
dotnet test tests/DoubleSync.Core.Tests/DoubleSync.Core.Tests.csproj
Demo Instances
Two Umbraco test instances are included for development and testing:
# Launch both with the helper script
powershell -ExecutionPolicy Bypass -File start-demo.ps1
# Or start individually
dotnet run --project demo-instances/dev/DemoUmbraco.Dev.csproj
dotnet run --project demo-instances/uat/DemoUmbraco.Uat.csproj
| Instance | URL | Login | Password |
|---|---|---|---|
| DEV | https://localhost:44311/umbraco | admin@demo-dev.test | DoubleSync1234! |
| UAT | https://localhost:44312/umbraco | admin@demo-uat.test | DoubleSync1234! |
API Credentials (auto-seeded):
| Instance | Client ID | Client Secret |
|---|---|---|
| DEV | umbraco-back-office-doublesync-dev |
doublesync-dev-secret |
| UAT | umbraco-back-office-doublesync-uat |
doublesync-uat-secret |
Start script options:
# Full build (frontend + backend + launch)
powershell -ExecutionPolicy Bypass -File start-demo.ps1
# Skip frontend build
powershell -ExecutionPolicy Bypass -File start-demo.ps1 -NoFrontend
# Skip backend build
powershell -ExecutionPolicy Bypass -File start-demo.ps1 -NoBuild
# Skip both builds
powershell -ExecutionPolicy Bypass -File start-demo.ps1 -NoBuild -NoFrontend
Frontend Development
The Umbraco backoffice frontend uses Lit web components with TypeScript and Vite:
cd src/DoubleSync.Umbraco/Client
# Install dependencies
npm install
# Build for production (output to wwwroot/App_Plugins/DoubleSync/)
npm run build
# Watch mode (rebuild on changes)
npm run dev
Key files:
| File | Purpose |
|---|---|
src/dashboard/doublesync-dashboard.element.ts |
Main dashboard component |
src/api/doublesync-api.ts |
TypeScript API client |
src/index.ts |
Entry point (imports dashboard) |
public/umbraco-package.json |
Umbraco extension manifest |
vite.config.ts |
Build configuration |
Umbraco UI components used: uui-tab-group, uui-tab, uui-box, uui-table, uui-button, uui-tag, uui-toggle, uui-loader-bar.
Packing & Publishing NuGet
# Pack all projects
dotnet pack src/DoubleSync.Core/DoubleSync.Core.csproj -c Release
dotnet pack src/DoubleSync.Cli/DoubleSync.Cli.csproj -c Release
dotnet pack src/DoubleSync.Umbraco/DoubleSync.Umbraco.csproj -c Release
# Publish to private feed
dotnet nuget push src/DoubleSync.Core/bin/Release/DoubleSync.Core.{VERSION}.nupkg \
--source https://nuget.double.pt/nuget --api-key YOUR_KEY
dotnet nuget push src/DoubleSync.Cli/bin/Release/DoubleSync.Cli.{VERSION}.nupkg \
--source https://nuget.double.pt/nuget --api-key YOUR_KEY
dotnet nuget push src/DoubleSync.Umbraco/bin/Release/DoubleSync.Umbraco.{VERSION}.nupkg \
--source https://nuget.double.pt/nuget --api-key YOUR_KEY
Version Bumping
Update the <Version> element in all three .csproj files:
src/DoubleSync.Core/DoubleSync.Core.csprojsrc/DoubleSync.Cli/DoubleSync.Cli.csprojsrc/DoubleSync.Umbraco/DoubleSync.Umbraco.csproj
Troubleshooting
| Problem | Solution |
|---|---|
| Connection refused / timeout | Ensure the remote instance is running and accessible. Check firewalls, HTTPS certs, and that the URL is correct. |
| 401 Unauthorized | Client ID or Client Secret is wrong, or the API User was deleted. Re-check credentials. |
| 403 Forbidden | API User lacks section permissions. Grant Content and Settings access. |
| Schema import: "parent not found" | Folder was deleted on target. Run a full schema sync to re-create the folder hierarchy. |
| Content import: "document type not found" | Schema must be synced first. Pull/Push handles this automatically; for manual commands, run schema-import before content-import. |
| Dashboard shows 404 | Ensure DoubleSync.Umbraco NuGet package is installed and the app has been restarted. The API runs at /umbraco/management/api/v1.0/doublesync/. |
| Frontend console errors | Clear browser cache and reload. Ensure the built JS is in wwwroot/App_Plugins/DoubleSync/. |
| Conflicts detected | Use --strategy source-wins, --strategy target-wins, or --interactive to resolve. |
License
DoubleSync is a commercial package with a free Community tier. See LICENSE.md for the full license agreement.
- Community (Free) — Schema sync and diff preview on up to 2 environments
- Pro — Full content, media, and people sync with merge editor
- Perpetual — Pro features with a one-time purchase for a specific Umbraco version
- Agency — Unlimited domains, Azure Blob Storage, scheduled snapshots, priority support
For pricing details, visit doublesync.io/pricing.
Copyright (c) 2026 Double Digital, Lda.
No packages depend on DoubleSync.Umbraco.
.NET 10.0
- DoubleSync.Core (>= 17.0.1-alpha.0.9)
- DoubleSync.Storage.Azure (>= 17.0.1-alpha.0.9)
- MailKit (>= 4.16.0)
- MessagePack (>= 3.1.7)
- Microsoft.Extensions.Http.Polly (>= 10.0.3)
- Microsoft.OpenApi (>= 2.3.0)
- MimeKit (>= 4.16.0)
- NSec.Cryptography (>= 25.4.0)
- Umbraco.Cms.Api.Management (>= 17.2.2)
- Umbraco.Cms.Web.Common (>= 17.2.2)
| Version | Downloads | Last updated |
|---|---|---|
| 17.0.1-alpha.0.25 | 0 | 02/09/2026 |
| 17.0.1-alpha.0.22 | 0 | 02/09/2026 |
| 17.0.1-alpha.0.21 | 0 | 02/09/2026 |
| 17.0.1-alpha.0.20 | 0 | 02/09/2026 |
| 17.0.1-alpha.0.19 | 0 | 02/09/2026 |
| 17.0.1-alpha.0.18 | 0 | 02/09/2026 |
| 17.0.1-alpha.0.16 | 0 | 02/09/2026 |
| 17.0.1-alpha.0.15 | 0 | 02/09/2026 |
| 17.0.1-alpha.0.14 | 0 | 02/09/2026 |
| 17.0.1-alpha.0.13 | 0 | 02/09/2026 |
| 17.0.1-alpha.0.12 | 0 | 02/09/2026 |
| 17.0.1-alpha.0.11 | 0 | 02/09/2026 |
| 17.0.1-alpha.0.10 | 0 | 02/09/2026 |
| 17.0.1-alpha.0.9 | 0 | 02/09/2026 |
| 17.0.1-alpha.0.8 | 0 | 02/09/2026 |
| 17.0.1-alpha.0.7 | 0 | 02/09/2026 |
| 17.0.1-alpha.0.6 | 0 | 02/09/2026 |
| 17.0.1-alpha.0.5 | 0 | 02/09/2026 |
| 17.0.1-alpha.0.4 | 0 | 02/09/2026 |
| 17.0.1-alpha.0.3 | 0 | 02/09/2026 |
| 17.0.0 | 0 | 02/09/2026 |
| 17.0.0-alpha.0 | 0 | 02/09/2026 |
| 1.0.0 | 0 | 02/09/2026 |
| 0.4.0 | 0 | 02/09/2026 |