Only this pageAll pages
Powered by GitBook
1 of 29

10.latest (LTS)

Loading...

Loading...

Loading...

Loading...

Installation

Loading...

Loading...

Upgrading

Loading...

Loading...

Getting Started

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Deployment Workflow

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Extending

Loading...

Loading...

Umbraco Deploy Documentation

Documentation on how to work with Umbraco Deploy.

Umbraco Deploy is a deployment tool that helps you with the process of transferring code and data between multiple environments. Deploy can be configured for many different setups and is great for both small setups as well as large and more complex infrastructures.

Umbraco Deploy is also the engine that runs behind the scenes on Umbraco Cloud. Here it takes care of all the deployment processes of both code, schema and content on projects.

With Umbraco Deploy you get to use the Umbraco Cloud Deployment technology outside of Umbraco Cloud to ease deployment between multiple Umbraco environments. This is done by connecting external hosted Umbraco projects with a local instance of your Umbraco website.

In the Umbraco Deploy documentation can read all about how to set up and work with Umbraco Deploy.

You can find articles about how to set up Umbraco Deploy on a new or an existing website, and article about the deployment workflow.

Legacy Documentation

This documentation platform covers only major versions of the Umbraco Deploy since Umbraco 9+. If you are using an older version of Umbraco Deploy, you will need to go elsewhere.

The documentation for Umbraco 7 and 8 lives on our.umbraco.com.

Umbraco 11 Documentation

Umbraco 8 Documentation

Configuration
Extend Deploy
Troubleshooting

Installing Umbraco Deploy

Learn how you can install Umbraco Deploy on new and existing Umbraco projects.

Deployment workflow in

Learn about how the Deployment workflow in Umbraco Deploy work.

Upgrading

Learn how you can upgrade Umbraco Deploy.

Upgrading Umbraco Deploy

How to upgrade Umbraco Deploy

As with all of our products, it is always recommended to run the latest version of Umbraco Deploy.

On the Umbraco Deploy page in the Packages page you can see what the latest version is, as well as read the changelog.

Umbraco Deploy can be upgraded via NuGet.

Open the Package Console in Visual Studio and type:

Update-Package Umbraco.Deploy.OnPrem

You will be prompted to overwrite files. You should choose "No to All" by pressing "L".

You can open the NuGet Package Manager and select the Updates pane to get a list of available updates. Choose the package called Umbraco.Deploy.OnPrem and click update. This will run through all the files and make sure you have the latest changes while leaving files you have updated.

Version Specific Upgrade Details

Contains version specific documentation for when upgrading to new major versions of Umbraco Deploy.

Getting started

How does Umbraco Deploy work and how to get started using Umbraco Deploy

In this article you can learn more about what it takes to get started using Umbraco Deploy. You can also get a high-level overview of how the product works.

How Umbraco Deploy works

Umbraco Deploy works by serializing non-content Umbraco items (called “Schema” items) to disk. These serialized files are located in the /umbraco/Deploy/Revision folder at the root of your website.

These items are entities like Document Types, Media Types, Data Types, etc, and these files must be committed to source control (for example Git). Umbraco Deploy works by “extracting” this serialized information back into your Umbraco installation. This is done by deployment triggers when a deployment is sent to a target environment.

For example, when working locally you might create a new Document Type. This will automatically create a new on-disk file in the umbraco/Deploy/Revision folder which is the serialized version of the new Document Type. You would then commit this file to your repository and push this change to your hosted source control (for example GitHub).

When you want this deployed to your next environment, you would trigger your CI/CD process (for example Azure DevOps or GitHub Actions). This will push the changes to your environment. Once the build deployment completes successfully, a Deployment Trigger would be executed as an HTTPS request to your target environment. All changes found in the umbraco/Deploy/Revision folder will then be extracted into the Umbraco target environment.

There are three main steps you need to go through in order to start using Umbraco Deploy on your website.

    • Set up a repository and then install a new Umbraco project inside it.

    • Umbraco Deploy can be installed via NuGet.

    • Umbraco Deploy needs a CI/CD build server needs to be set up to run when you want changes to be deployed to next upstream environment

CI/CD Build and Deployment Pipeline

Steps and examples on how Umbraco Deploy can be integrated into an automated build and deployment pipeline

Once Umbraco Deploy has been installed and the schema data has been generated, a CI/CD build server needs to be set up.

The build server will extract the changes that has been pushed to the repository into your production website that has been connected with Umbraco Deploy.

This is something that can be done in many different ways depending on where your website is hosted and your setup.

Umbraco Deploy does not require the use of any particular build or deployment tools and hence we expect that you should be able to continue using the tool or tools of your choice. Any that have support for .NET website deployments and the running of Powershell scripts. such as Azure DevOps or GitHub Actions, would be appropriate.

Above and beyond the normal steps of a build pipeline for a .NET web application - tasks like NuGet restore, solution build, running of tests etc. - Umbraco Deploy requires three additional steps.

  • The license file needs to be deployed into the target environment's umbraco/Licenses folder.

  • The .uda schema files that are written to disk and included in source control, need to be made available in the build artifact that is deployed to the target environment.

  • Once the build is complete, the extraction of the updated schema in the target environment needs to be triggered.

The first two steps will be implemented in a similar way. There will need to be a step added to the pipeline that runs after the main build of the website, to copy the license file and data files into the published build output, such that they are included in the build artifacts that are deployed to the target environment.

The third step needs to run last in the pipeline, once the built web application is deployed to the target environment. Umbraco Deploy provides a Powershell script that can be used for the purpose of triggering the extraction of the schema information and update of the target Umbraco installation.

Background on the Schema Extraction Process

Without a CI/CD pipeline step in place to trigger the extraction, following a deployment, the process would need to be carried out manually. This can be done by logging into the backoffice, navigating to Settings > Deploy and triggering the operation via the dashboard.

Behind the scenes what happens here is a marker file being written to disk - in the /umbraco/Deploy/ folder and with a name of deploy. It’s by monitoring this directory for a file with this name that Umbraco Deploy knows to trigger the extraction.

Umbraco Deploy also provides an HTTPS endpoint that can be called by an authenticated request. This will write the marker file, which will trigger the extraction.

Umbraco Deploy On-Premises also ships with a Powershell script, that when executed will call the endpoint, which will write the file, and which will trigger the extraction.

So while it may be possible to have the CI/CD step directly write the file or call the endpoint, so long as the build used supports running Powershell scripts this is the method we’d recommend, as it has some necessary error checking and retry logic built-in.

Details the setup of a CI/CD pipeline using GitHub Actions.

Details the setup of a CI/CD pipeline using Azure DevOps.

Streamlining Local Development

In this section we discuss some additional steps you can carry out to streamline your local development workflow.

Creating Git Hooks

Working in a team, it's common for developers to pull code from source control to update their local environment with the latest Umbraco schema.

They can do this by starting up the website, navigating to the Settings > Deploy dashboard and triggering a data extraction.

We can automate this step using a .

When working with Umbraco Cloud, this step is configured automatically for you when you clone and run your project the first time. If working with Umbraco Deploy On-Premise, you can set it up yourself.

The process works by using the marker file Umbraco Deploy uses to trigger an update of the Umbraco schema from the .uda files from source control.

If a file named deploy-on-start is found in the /umbraco/Deploy folder, an update will run automatically when the site starts up.

Therefore, if we ensure that the file is created everytime the source code is pulled from the remote repository, we can automate the update.

To do this, carry out the following steps:

  • Find the .git folder within your solution root.

    • It might be a hidden folder, so if you don't see it, make sure your file browser is configured to show hidden files and folders.

  • Within that you'll find a hooks folder, and inside that, a file called post-merge.sample.

  • Rename the file to remove the .sample extension and open it in a text editor.

  • Apply the following text and save the file (amending the path to the web project as appropriate for your solution structure):

  • Run a git pull origin <branchname>.

  • Start up the website and you should find the Umbraco schema update has been triggered.

Setting up CI/CD pipeline with GitHub Actions
Setting up CI/CD pipeline with Azure DevOps
#!/bin/sh
echo > src/UmbracoProject/umbraco/Deploy/deploy-on-start
git hook
Quick start (new sites)
Set up Git repository and new Umbraco project
Install Umbraco Deploy via NuGet
Configure CI/CD build server
Deploy workflow

Deploy Dashboard

With the Deploy Dashboard, we have made it possible to get an overview of your Umbraco Deploy installation and perform Deploy operations.

In this article, we will show the different sections on the Deploy dashboard and how they can be used.

Deploy Status

Here you can see whether the latest deployment has been completed or failed. You can see the version of Umbraco Deploy you are running, and the last time an operation was run.

Umbraco Deploy status

Deploy Operations

With the Deploy operations, you can run different operations in Umbraco Deploy.

The different Deploy operations.

Below you can read what each operation will do when run through the dashboard.

Update Umbraco Schema From Data Files

Running this operation will update the Umbraco Schema based on the information in the .uda files on disk.

Export Schema To Data Files

Running this operation will extract the schema from Umbraco and output it to the .uda files on disk.

Clear Cached Signatures

Running this operation will clear the cached artifact signatures from the Umbraco environment. This should not be necessary, however, it may resolve reports of schema mismatches when transferring content that has been aligned.

Set Cached Signatures

This operation will set the cached artifact signatures for all entities within the Umbraco environment. Use this when signatures have been cleared and you want to ensure they are pre-generated before attempting a potentially longer restore or transfer operation.

Download Deploy Artifacts

Running this operation will download a zip file with all the Deploy artifacts representing the Umbraco schema in the form of .uda files.

This operation is useful if you want to move to another Umbraco instance and migrate the data with you.

Donwload the Deploy artifacts

Configuration Details

In the Configuration details, you can see how Umbraco Deploy has been configured on your environment. You get an overview of the Setting options, the current value(s), and notes help you understand each of the settings. Updates to the need to be applied in the appsettings.json file.

Example of Umbraco Deploy configuration.

Schema Comparison

The Schema Comparison table shows the schema information managed by Umbraco Deploy.

You can see a comparison between the information that is held in Umbraco and the information in the .uda files on disk.

The table shows:

  • The name of the schema

  • The file name

  • Whether the file exists in Umbraco

  • Whether the file exists

  • Whether the file is up-to-date

Document type schema comparison

You can also view details about a certain element by selecting "View Details".

This will show the difference between entities stored in Umbraco and the .uda file stored on disk.

Showing how you can compare schema in the deploy dashboard

Deployment

A description of the proper workflow when working with Umbraco Deploy

Umbraco Deploy uses a deployment model that relies on Git and Umbraco Deploy core technology to move your changes from one environment to another. Umbraco Deploy uses a classic "left to right" deployment model, meaning that changes are first made in the Development or local environment and then deployed to the production environment.

If your project contains a Staging environment, deployments will be made from Development to Staging and then from Staging to Live.

Deployment Approach

Umbraco Deploy uses a two-part deployment approach where we keep meta data (Document types, templates, etc) and content (Content nodes and Media) as separate parts of a deployment. In order to be able to distinguish between the two types of deployments we use the term transfer for content and media deployments and the term deploy for meta data deployments.

In summary:

  1. Meta data such as Document Types, Templates, Forms, Views and config files are stored in a repository and are deployed between environments. This can be achieved using a CI/CD deployment pipeline with something like GitHub Actions or Azure DevOps.

  2. Content and Media items are not stored in the repository. These need to be transferred directly from the Umbraco backoffice using the "Queue for Transfer" option. Once a content editor has all the items needed for a transfer they will use the Deployment Dashboard in the Content section to transfer the items in the queue.

Deploying meta data

In order to be able to transfer content and media, the source environment and the target environment needs to have the same setup - meaning they need to be completely in sync and have the same file structure. To achieve this you need to deploy your meta data changes to the target environment.

Transfer Content and Media

Moving your content and media between your environments is done through the Umbraco backoffice. You can transfer content from one environment to another, e.g. from local to your development environment. You also have the option to restore content and media to your local or development environment from your production or staging environment.

Transferring and restoring content and media is the same whether you are working locally and transferring between two environments.

Import and Export

Another approach for transferring content and schema between environments is to use import and export. In one environment, you can export selected content, a tree, or the whole workspace to a .zip file. There are options to include related media files, schema and code files such as templates and stylesheets.

That .zip file can then be uploaded into a new environment, where it will be validated and then processed to update Umbraco.

As part of the import process, we provide hooks to allow for migrations of the imported artifacts (like data types) and property data. This should allow you to migrate your Umbraco data from one Umbraco major version to a newer one.

We recommend using the content and media backoffice transfer options for day-to-day editorial activities. Import and export is intended more for larger transfer options, project upgrades, or one-off tasks when setting up new environments.

Read more about the .

Deploy Dashboard

In Umbraco Deploy we have included a Deploy Dashboard in the Settings section of the Umbraco backoffice to make it easier to run operations like schema deployment from data files and extract schema to data files.

When running the extract schema to data files operation, Umbraco Deploy will run an echo > deploy-export in the data folder of your project which is used to generate UDA files based on the schema in your database.

Running the schema deployment from data files operation will initiate an extraction on the environment

The extraction will end in one of two possible outcomes:

  1. deploy-complete: The extraction succeeded and your environment is in good shape!

  2. deploy-failed: The extraction failed - open the deploy-failed file, to see the error message.

It is also possible to see which version of Umbraco Deploy you are running, when the last operation was started and the status of the deployment operation.

In Umbraco Deploy we have included a Deploy Dashboard in the Settings section of the Umbraco backoffice to make it easier to run operations like schema deployment from data files and extract schema to data files.

Deploying Changes

How to Deploy changes between a local machine and an environment in Umbraco Deploy using either a Git Gui or without

In this article you can learn more about how to deploy your code changes and meta data from a local instance to a remote environment.

Deploying from local to your environments

When you are working with your Umbraco project locally all changes you make will automatically be identified and picked up by your local Git client.

Here's a quick step-by-step on how you deploy these changes to your environment:

  • You've cloned a site to your local machine to work on.

  • You've made some changes to a Document Type.

  • The corresponding .uda file for this Document Type is now updated with the changes - the file is located in the /umbraco/Deploy/Revision folder.

  • You've also created a new Data Type that's used on the Document Type. This Data Type is stored as a new file in the /umbraco/Deploy/Revision folder as well.

  • Using Git, commit those two changed files to your local repository and push them to your repository.

  • A deployment kicks in and the Document Type is updated and the new Data Type you created locally is now automatically created in the remote environment as well.

Deploying without using a Git client

If you don't have a Git client installed on your local machine, you can use Git or Git Bash for command-line Git operations. Run the following commands:

When pulling new commits, it is a good idea to see if any of these commits contained changes to the schema (anything in umbraco/Deploy/Revision/). To ensure your local schema is up-to-date, you can navigate to the umbraco/Deploy/ folder and create a deploy marker if it doesn't exist. From a command line type the following command:

/…mysite/umbraco/Deploy> echo > deploy

The local site should be running when you do this. The deploy marker will change to deploy-progress while updating the site and to deploy-complete when done. If there are any conflicts/errors you will see a deploy-failed marker instead, which contains an error message with a description of what went wrong.

Another way is to use the Deploy Dashboard in the Settings section of the Umbraco backoffice. Here you can see the status of ongoing or completed deployment processes. The status will show whether an operation has been triggered and whether it is in progress, has completed or has failed. The dashboard will show the status based on the marker files on the disk, eg. deploy-progress. From the Deploy Dashboard it is also possible to trigger processes. Learn more about this dashboard in the article.

# Navigate to the repository folder
cd mySite
# Check status of the repository for pending changes
git status
# Add pending changes
git add -A
# Commit staged files
git commit -m "Adding updated schema changed"
# Push to the environment
git push

# If the push is rejected you will need to pull first
git pull
# Try to push again if there were no conflicts
git push
Deployment

Licensing

Umbraco Deploy is a commercial product. You will need a valid license to use the product.

How does it work?

Licenses are sold per domain and will also work on all subdomains. With every license, you will also be able to configure two development/testing domains.

The licenses are not bound to a specific product version. They will work for all versions of the related product.

Example

Let's say that you have a license configured for your domain, mysite.com, and you've configured two development domains, devdomain.com and devdomain2.com.

The license will cover the following domains:

  • localhost

  • *.mysite.com

  • www.mysite.com

  • mysite.com.local

  • devdomain.com

  • www.devdomain.com

  • devdomain2.com

  • www.devdomain2.com

You can have only 1 license per Umbraco installation.

What does a license cover?

There are a few differences as to what the licenses cover:

A single license covers one Umbraco solution. It includes all domains hosted by the solution, all production environments (if load-balancing), and all non-production environments.

To clarify the above:

  • You only need one license when you have a solution covering multiple domains- for example, www.mysite.com and www.mysite.dk - load balanced in production over multiple servers running from the same database, managed from the same backoffice instance, and with any number of non-production environments (staging, QA, etc.)

  • You need two licenses if you have a web presence that consists of two separate websites hosted on different domains or sub-domains - for example, www.mysite.com and shop.mysite.com - with each of these managed as a separate Umbraco installation using their own database and backoffice in production.

The license for Umbraco Deploy comes with a recurring yearly fee. Learn more about this and pricing on Umbraco.com.

Configuring your license

You can look at the pricing, plans, features, and purchase the license on the Umbraco Deploy On-premises page.

When you've bought a license you need to configure it with your domains. You can either configure your license right away, or you can do it later by visiting your account on Umbraco.com.

Installing your license

Once you've configured your license with the correct domains, you are ready to install the license on your Umbraco installation.

  1. Download your license from your Umbraco.com account - this will give you a .lic file

  2. Place the file in the /umbraco/Licenses directory in your Umbraco installation

The .lic file must be placed in the /umbraco/Licenses directory in order to be registered by Umbraco Deploy.

Alternative license location

If you can't include the license file in the /umbraco/Licenses directory for any reason it is possible to configure an alternative location for the file.

It can be configured in the Umbraco installation's appSettings.json file by adding the following appSetting. The value contains the path of your custom license directory relative to the root of your Umbraco installation.

This will also change the location for other Umbraco-related licenses in this project.

{
  "Umbraco": {
    "Licensing": {
        "Directory": "~/custom-licenses-folder/"
    }
  }
}

Azure DevOps

Steps and examples on how to setup a build and deployment pipeline for Umbraco Deploy using Azure DevOps.

In this section, we provide a full example of how Umbraco Deploy running on Umbraco 9 and above can be utilized. This can be used as a part of a build and deployment pipeline using Azure DevOps. You can use this directly or adapt it for your needs.

Discussion on the Provided Example

We have defined a single stage build and deployment pipeline, configured in YAML format. While not as visually intuitive as a drag-and-drop task list, it provides the advantage of source control management.

We then have a number of variables defined, that are used in the build configuration below. By using variables we have the ability to modify the script for use on other web applications. Some values are set in the script, and some via Azure DevOps variables or secrets.

Most tasks in the pipeline are standard steps that will be used in any .NET web application release, such as the first steps:

#1 Install of the NuGet tooling,

#2 Restore of NuGet dependencies,

#3 And the project build.

Additional steps can be added as required, for example for running automated tests.

The Umbraco Deploy license file and the schema data files will automatically be included within the build output.

The deployment part of the pipeline stage consists of two steps.

Firstly a web deployment (#4), takes the packaged build artifact and deploys it, in this case, to an Azure Web App slot.

The final step (#5) is Umbraco Deploy specific - to call a function defined in the Powershell script and trigger the extraction.

The Microsoft docs contain useful information, if you are unsure of how to set secrets for your pipeline:

  • Set secret variables

  • Protecting secrets in Azure Pipelines

Full Example

trigger:
- main

pool:
  vmImage: 'windows-latest'

variables:
  solution: '**/*.sln'
  buildPlatform: 'Any CPU'
  buildConfiguration: 'Release'

  vsSolutionName: DeployOnPremSite
  vsProjectName: DeployOnPremSite
  umbracoDeployTriggerDeploy: $(Build.SourcesDirectory)\$(vsSolutionName)\$(vsProjectName)\TriggerDeploy.ps1
  umbracoDeployReason: AzureDeployment

  deployApiKey: <set in Azure Pipeline secret>
  azureSubscription: <set in Azure Pipeline variable>
  webAppName: <set in Azure Pipeline variable>
  resourceGroupName: <set in Azure Pipeline variable>
  deploySlotName: <set in Azure Pipeline variable>
  deployBaseUrl: <set in Azure Pipeline variable>

steps:
#1 NuGet Tool Install
- task: NuGetToolInstaller@1
  displayName: Install NuGet

#2 NuGet Restore
- task: NuGetCommand@2
  displayName: Restore NuGet packages
  inputs:
    restoreSolution: '$(solution)'

#3 Build the VS Solution and publish the output to a zip file
- task: VSBuild@1
  displayName: Build solution
  inputs:
    solution: '$(solution)'
    msbuildArgs: '/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:DesktopBuildPackageLocation="$(build.artifactStagingDirectory)\WebApp.zip" /p:DeployIisAppPath="Default Web Site"'
    platform: '$(buildPlatform)'
    configuration: '$(buildConfiguration)'

#4 Deploy to an Azure web app slot
- task: AzureRmWebAppDeployment@4
  displayName: Deploy to web app
  inputs:
    ConnectionType: 'AzureRM'
    azureSubscription: '$(azureSubscription)'
    appType: 'webApp'
    WebAppName: '$(webAppName)'
    deployToSlotOrASE: true
    ResourceGroupName: '$(resourceGroupName)'
    SlotName: '$(deploySlotName)'
    packageForLinux: '$(build.artifactStagingDirectory)\WebApp.zip'

#5 Trigger the Umbraco Deploy extraction
- task: PowerShell@2
  displayName: Run PowerShell script
  inputs:
    filePath: '$(umbracoDeployTriggerDeploy)'
    arguments: '-InformationAction:Continue -Action TriggerWithStatus -ApiKey $(deployApiKey) -BaseUrl $(deployBaseUrl) -Reason $(umbracoDeployReason) -Verbose'
Deploying from your local machine to your environments
Transfer Content and Media
Restore Content and / or Media
import and export feature
Deploy Dashboard
Left to right model

Transferring Content, Media and Forms

How to restore content in Umbraco Deploy using the deployment dashboard

Once all code and meta data is in sync between your environments, it's time to transfer your content and media. This is done from the Umbraco Backoffice.

Content and media transfers are flexible which means you have complete control over which content nodes and/or media items you want to transfer. You can transfer it all in one go, a few at a time or transfer only a single node.

Transferring content will overwrite any existing nodes on the target environment - content transfers will transfer the items that you select in the "source" environment to the "target" environment exactly the same as it was in the "source". This means that if you have some content on the target environment already, this will be replaced by the new content from the source environment.

Important: Content and Media transfers will only work if you've deployed all changes to your meta data before hand. Please refer to our documentation on how to deploy meta data from Deploying Content.

Step-by-step

Let’s go through a content transfer step by step. Imagine you’ve finished working on new content for your project locally and you are ready to transfer the changes to your development site.

You want to transfer the whole site. You start from the Home node and choose to transfer everything under it:

  1. Click on the ellipsis next to the Home node in the Content tree.

  2. Choose "Do something else".

  3. There you get the choice of Queue for transfer.

    • If you’re currently editing the Home page you could also use the Actions dropdown to find Queue for transfer.

  4. Choose if you want to include all pages under the chosen page or only transfer the chosen node.

    • If you wish to transfer all your content at once, right-click the top of the Content tree where you will also find Queue for transfer - this will queue all your content for transfer.

  5. Select the language versions that you want to queue for transfer. Only languages for which you have permission to access will be selectable.

  6. Set the publish date and time if you want to change when the transferred content should be published.

    By default, the content will be transferred in its current published state. So if the content is published in the current environment, the changes will be deployed and the item immediately be published in the destination. If you prefer to schedule the publishing of the changes, you can do so by selecting a publish date.

  7. Click Queue to add the content item to the transfer queue.

    Queue for transfer window
  8. Go to the Deployment dashboard by clicking on the Content section header.

    • You will be able to see which items are currently ready to be transferred - this will include both content and media that you've queued for transfer.

  9. Confirm by clicking Transfer toDevelopment and monitor the progress of the transfer.

    Transfer queue

If everything went well, you will see the confirmation screen saying that the transfer has succeeded.

Media items

Media items are transferred the same way as content:

  1. In the Media section Right-click the items you want to transfer and choose Queue for transfer.

    • Or right-click the top of the Media section to transfer all you media at once.

  2. Go to the Deployment dashboard in the Content section to see the items you've queued for transfer and to transfer your items.

Umbraco Forms

In order for Deploy to handle Forms data as content, you will need to ensure that the transferFormsAsContent setting in configuration is set to true. See details in the Deploy Settings for Umbraco 9+ article.

Once the setting have been added to the source and target environment forms can be transferred the same way as content and media:

  1. In the Forms section Right-click the items you want to transfer and choose Queue for transfer.

    • Or right-click the top of the Forms section to transfer all your Forms at once.

  2. Go to the Deployment dashboard in the Content section to see the items you've queued for transfer and to transfer your items.

This does not include entries submitted via the forms.

Schema Mismatches

Sometimes a content transfer might not be possible. For example if you add a new property to the HomePage Document type and you don’t have that property in both environments, you’ll get an error with a hint on how to fix this.

Clone dialog

If you are seeing this type of issue when trying to transfer content, head over to our article about Schema Mismatch errors, where you can read about how to resolve the issues.

Restoring content

How to restore content in Umbraco Deploy

When you have content on your environment and you clone down your Umbraco project to your local machine, you will need to do an extra step, in order to see your content locally.

The restore option also comes in really handy when you have content editors creating content on different environments. You will be able to restore and work with that content on your different environments and locally.

Step-by-step

There are four options when it comes to restoring content.

  1. Restore when starting up the project locally

  2. Restore everything through the Umbraco backoffice

  3. Restore a single tree through the Umbraco backoffice

  4. Partial Restores

Restore when starting up the project locally

The first time you run your project locally you will have the option to restore your content and media before going to the Umbraco backoffice.

This will restore all content and media, plus any other entities configured for back-office transfer.

  1. When your site is done spinning up, click the green Restore button - this will restore all content and media.

  2. Wait till the process completes - this might take a while, depending on the amount of content and media you have on your Umbraco site.

  3. When it's complete select Open Umbraco to go to the backoffice.

  4. You will now see all your content and media in the Umbraco backoffice.

Restore from start-up

Restore everything through the Umbraco backoffice

The second option for restoring your content and media is found in the Umbraco backoffice.

  1. Go to the Umbraco backoffice on the environment you want to restore content and media to.

  2. Click the three dots an select Do something else, or Right-click the Content Tree.

  3. Choose Workspace restore... from the menu.

  4. You will now have the option to restore content from any environment that's to the right of the current environment in the deployment workflow.

  5. To ensure the restore will succeed, make sure that your environments have the same meta data and structure files.

  6. Click Restore from .. and wait till the process completes - this might take a while, depending on the amount of content and media you have on your project.

  7. When it's done, right-click the Content tree again and choose Reload to see your content in the tree.

As well as content, media and any other entities configured for back-office transfer, will also be restored in the process.

To see the media, go to the Media section and Reload the tree.

Restore a single tree through the Umbraco backoffice

The operation is triggered in the same way as when restoring everything, but instead the Tree restore... menu option should be selected.

For example, if triggered from the content tree, only content entities will be restored. This will also restore any media that’s referenced in that content, but it won’t attempt to restore the full media library, nor any other entities.

Partial Restore

By using the Partial Restore option, you can make sure that you only restore the part of the content that you need to work with. You can either restore a single item, or include all the descendents of that item too.

Deploying deletions

How deleting meta data and files work in Umbraco Deploy

With Umbraco Deploy deletions are environment specific. This means that in order to delete something entirely from your project, you need to delete it on all environments.

In this article you can read about the correct way of deleting files, schema and content when using Umbraco Deploy.

When you are using Umbraco Deploy, you might have more than one environment - including a local clone of the project. These environments each have their own database. The databases will contain references to all of your content and media, as well as to all of your schema files (e.g. Document Types, Templates etc).

The databases are environment specific. When you deploy from one environment to another, Umbraco Deploy will compare incoming schema files with references to these in the databases using both alias and GUID. If something doesn't add up - e.g. there is a mismatch between the database references and the files deployed - you will see an error. Learn more about this in the Troubleshooting section.

The workflow described above does not pick up deletions of content and schema from the database, which is why you'll need to delete the content and/or schema on all your environments, in order to fully complete the deletion.

The main reason Umbraco Deploy does not delete schema and content on deployments, is because it could lead to unrecoverable loss of data. Imagine that you delete a Document Type on your Development environment, and push this deletion to your production environment where you have a lot of content nodes based on the deleted Document Type. When the deployments goes through, all of those content nodes would be instantly removed with no option to roll back as the Document Type they are based on no longer exists. To avoid anyone ending up in this unfortunate situation, deletes are not automatically handled and will require an active decision from you on each environment in order to take place.

Example scenario

Let's say you've deleted a Document Type on your Development environment, and now you want to deploy this deletion to the production environment.

Before you deploy the changes, in Git it will show that the following changes are ready to be committed and deployed:

Changes ready for deployment

Commit the changes and push them to your repository and trigger a deployment to your environment.

Once the deployment is complete, you will notice the following:

  • The Document Type you deleted on Development is still present in the backoffice on the production environment.

You might wonder why the Document Type that you have deleted, is still there. The reason is, that deploy only deletes the associated UDA file, and not the actual Document Type in the database.

In order to completely delete the Document Type from your entire project, you need to delete it from the backoffice of any of the other environments you have as well. When the Document Type has been deleted from the backoffice of all environments and no UDA file exists, you can consider it completely gone.

You should however keep in mind that if you at any point during the process, save your Document Type again, a UDA file will be regenerated and when you start deploying changes between environments, this will likely end up recreating your deleted Document Type.

Which deletions are deployed?

Every file that's deleted, will also be deleted on the next environment when you deploy. However, there are some differences depending on what you have deleted.

Here's an overview of what happens when you deploy various deletions to the next environment.

Deleting Schema (Document Types, Datatypes etc.)

Deleted:

  • The associated .uda file.

Not deleted:

  • The entry in the database.

  • The item will still be visible in the backoffice.

Deleting a Template

Deleted:

  • The associated .uda file.

  • The associated .cshtml file (the view file).

Not deleted:

  • The entry in the database.

  • The template file will be empty, but still be visible in the backoffice.

Deleting files (css files, config files etc.)

As these are only files, everything will be deleted on the next environment upon deployment.

Deleting content and / or media

Content and media deletions will not be picked up by deployments and will have to be deleted on each environment you wish to delete the content or media on.

Deleting backoffice languages

Deleted:

  • The associated .uda file

Not deleted:

  • The entry in the database

  • The language will still be visible in the backoffice/content dashboard (for multilingual content)

Deleting the language in the backoffice on the target environment will ensure the environments are in sync.

Troubleshooting

The troubleshooting section for Umbraco Deploy

In this troubleshooting section, you can find help to resolve issues that you might run into when using Umbraco Deploy.

If you are unable to find the issue you are having, then please reach out to our friendly support team at [email protected].

Schema mismatches

When transferring or restoring content between two Umbraco Deploy environments, you might run into Schema mismatch errors. For more information on how to resolve schema mismatch issues, see the article.

Umbraco Deploy maintains a cached set of signatures that represent each schema and content item. They are used when transferring or restoring content between environments to aid performance.

If having resolved schema mismatches you still have reports of errors, it might be that the signatures are out of date. In other words, Deploy is using a cached representation of an item that no longer matches the actual item stored in Umbraco.

This should not be necessary in normal use, but can occur after upgrades. If you have this situation, you can clear the cached signatures in both the upstream and downstream environments. You do this via the Clear Cached Signatures operation available on the Settings > Deploy dashboard:

Slow responses or timeouts when restoring or transferring

When transferring or restoring content between environments, Deploy needs to ensure that all related items are updated together. It also checks that any schema dependencies an item has also exist in the target environment. When a large amount of content is selected for transfer or restore, this process of determining all the dependent items can take some time.

In some cases, a hard limit imposed by the Cloud hosting platforms such as Azure, used by Umbraco Cloud, can be reached.

If you find the process slow or reporting a platform timeout, there are a few options you can take.

Consider partial restore

If restoring, you can choose to pull down a smaller set of content via the partial restore feature. With this you select an item in the remote environment to restore. You can select to include child items. Any items related to the selected ones, for example via content or media pickers, will also be restored.

Consider import/export

In addition to transferring content via the backoffice, it is possible to move both content and schema between environments via Deploy's import/export feature. With this, a selection of Umbraco data can be exported from one environment to a .zip file. That file can then be imported into another environment.

As this process requires less inter-environment communication, it's possible to transfer much larger amounts of content without running into the hard platform limits.

.

Review timeouts

Firstly, you can review and update the . Increasing these from the default values may help, but won't necessarily resolve all issues. This is because, as noted, some timeouts are fixed values set by the hosting environment.

Use batch configurations

There are two places where Deploy operations can be batched. This allows breaking up of a single, long process into multiple, smaller ones. By doing this it's possible to complete each smaller operation within the platform imposed timeout.

For transfers to upstream environments

If transferring items from a downstream environment to an upstream one, it's possible to . With this in place, transfers will be batched into separate operations, allowing each single operation to complete before any hosting environment-enforced timeout.

This will take effect only for transfers to upstream environments and when multiple items are selected in the backoffice. An example is the selection of a single media folder containing many files.

For processing of a Deploy "package"

A package is an ordered structure containing all the items selected for a Deploy operation, plus all the determined dependencies and relations. The processing of this package in the target environment can also be batched via a .

When set, if the number of items determined for the package exceeds the batch size, the processing will be chunked into batches.

Ensure signatures are pre-cached

For transfer or restore operations, it's worth ensuring Deploy's cached signatures are fully populated in both the upstream and downstream environments. This can be done via the Set Cached Signatures operation available on the Settings > Deploy dashboard:

The process make take a few minutes to complete if you have a lot of content or media in your installation. Information is written to the log indicating the signatures calculated for each entity type.

Now the checks Deploy has to do to figure out the items and dependencies to process will complete much more quickly.

Modify the checksum calculation method for media files

Deploy will do comparisons between the entities in different environments to determine if they match and decide whether to include them in the operation. By default, for media files, a check is made on a portion of the initial bytes of the file.

If a lot of files need to be checked, this can be slow, and a faster option is available that uses the file metadata. The only downside of changing this option is a marginally increased chance of Deploy considering a media file hasn't changed when it has. This would omit it from the deployment.

This option can be .

Consider disabling cache refresher notifications

When a Deploy operation completes, cache refresher notifications are fired. These are used to update Umbraco's cache and search index.

In production these should always be enabled, to ensure these additional data stores are kept up to date.

If attempting a one-off, large transfer operation, before a site is live, you could disable these via a . That would omit the firing and handling of these notifications and remove their performance overhead. Following which you would need to ensure to rebuild the cache and search index manually via the backoffice Settings dashboards.

Review relation types included in deploy operations

As well as transferring entities between environments Deploy will also include the relations between them. As of 10.1.2 and 11.0.1, two relation types used for usage tracking are omitted by default. These do not need to be transferred as they are recreated by the CMS as part of the save operation on the entity.

If using an earlier version, or to make further adjustments, modify the in configuration.

Path too long exceptions

When restoring between different media systems exceptions can occur due to file paths. They can happen between a local file system and a remote system based on blob storage. What is accepted on one system may be rejected on another as the file path is too long. Normally this will only happen for files with particularly long names.

If you are happy to continue without throwing exceptions in these instances you can . If this is done such files will be skipped, and although the media item will exist there will be no associated file.

Schema files following upgrades

When Umbraco schema items are created, a representation of them is saved to disk as a .uda file in the /data/revision/ folder. The representation is known as an artifact. It will be refreshed on further updates to represent the current state of the schema item.

Following an upgrade, it's possible the contents of the file will no longer match what would be generated by the current version. For example, if a property has been added to an artifact, this will be absent in the file. It would be added if the file was recreated following the upgrade.

This can lead to situations where Deploy continues to process a file it considers changed, even though the item represented is up-to-date. This in turn means slow updates of Umbraco schema, as Deploy is processing more files than it needs to do.

To resolve this situation, following an upgrade it is good practice to re=save the .uda files in the "left-most" environment. This will usually be the local one, or if not using that, the Development environment. You can do this via the Export Schema To Data Files operation available on the Settings > Deploy dashboard:

The updated files should be committed to source control and deployed to upstream environments.

Version Specific Upgrade Details

Version specific documentation for upgrading to new major versions of Umbraco Deploy.

This page covers specific upgrade documentation for when migrating to major 10 of Umbraco Deploy.

If you are upgrading to a minor or patch of Deploy you can find the details about the changes in the article.

Version Specific Upgrade Notes History

Version 10 of Umbraco Deploy has a minimum dependency on Umbraco CMS core of 10.0.0. It runs on .NET 6.

The forms deployment component has a minimum dependency on Umbraco Forms of 10.0.0.

To migrate to version 10 you should first update to the latest minor release of version 9. This will ensure you have all the database schema changes in place.

Breaking changes

Version 10 includes a number of breaking changes. These changes are unlikely to affect many projects because they're not in typical extension points. For reference though, the full details are listed here.

Database Initialization

When using Umbraco Deploy with Umbraco Cloud, a development database is automatically created when restoring a project into a local environment for the first time. With Umbraco 9 and previous versions, SQL CE could be used for this. This database type is no longer supported in Umbraco 10, so SQLite is available instead. SQLite will be the default format used for the local database.

If you prefer to use a supported alternative, you can ensure that a connection string is in place before triggering the restore operation.

For example, to use a local SQL Server Express instance, you would place this in your appSettings.json configuration file:

If you prefer to use LocalDB, either set a connection string as above:

Or set the configuration value of Umbraco:Deploy:Settings:PreferLocalDbConnectionString to true:

If you are upgrading from Umbraco 9 and already have a LocalDB instance, you can set this value to true. This will ensure it is used rather than a new, empty SQLite database.

Configuration

  • The boolean property IgnoreBrokenDependencies has been removed, and the option is now controlled only by the IgnoreBrokenDependenciesBehavior configuration key, which takes an enumeration value.

    • The default value has changed to IgnoreBrokenDependenciesBehavior.Restore, as this will most likely be what developers require (allowing broken dependencies when restoring, but not when pushing to an upstream environment).

  • CurrentWorkspaceName has been added to the Project configuration section. This will be used by on-premises installations.

    • Previously this used EnvironmentName in the Debug configuration section, which will still be used if defined to support upgrades. We recommend using the new configuration as it's more intuitively placed (that is not really a "debug" setting for on-premises installations).

Code

  • The following classes have altered constructors taking additional parameters.

    • DeployScopeProvider

    • ArtifactRelator

    • RepairDictionaryIdsWorkItem

    • DiskWorkItemFactory

    • ClearSignaturesWorkItem

    • MemberTypeConnector

    • DeployManagementDashboardController

    • CurrentEnvironment

  • Additional methods have been added to IUmbracoEnvironment.

  • The property BackOfficeDeployOperation has been added to IWorkItem.

  • The RelationTypeArtifact class has been moved to the Umbraco.Deploy.Infrastructure.Artifacts namespace.

  • IDiskEntityService has been moved to the Umbraco.Deploy.Infrastructure.Disk namespace.

  • An additional method, previously provided by an extension method, has been added to the IDiskEntityService interface.

  • DiskReadTask has been moved to the Umbraco.Deploy.Infrastructure.Work.BackgroundTasks namespace.

  • ITransferEntityService.RegisterTransferEntityType has an additional parameter.

  • DeployRegisteredEntityTypeDetail was renamed to DeployTransferRegisteredEntityTypeDetail.

  • Removed unused class SerializablePropertyValue.

Legacy version specific upgrade notes

You can find the version specific upgrade notes for versions out of support in the .

{
  "ConnectionStrings": {
    "umbracoDbDSN": "Server=.\\SQLEXPRESS;Database=UmbracoDb;Integrated Security=true",
    "umbracoDbDSN_ProviderName": "Microsoft.Data.SqlClient"
  }
}
{
  "ConnectionStrings": {
    "umbracoDbDSN": "Data Source=(localdb)\\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\\Umbraco.mdf;Integrated Security=True",
    "umbracoDbDSN_ProviderName": "Microsoft.Data.SqlClient"
  }
}
{
    "Umbraco": {
        "Deploy": {
            "Settings": {
                "PreferLocalDbConnectionString": true
            }
        }
    }
}
release notes
Legacy documentation on GitHub
Schema Mismatches
Read more about the import/export feature here
timeout settings available with Deploy
configure a batch size
configuration setting
set in configuration
configuration setting
settings for relation types
modify the configuration
Clear cached signatures
Set cached signatures
Export schema

GitHub Actions

Steps and examples on how to setup a build and deployment pipeline for Umbraco Deploy using GitHub Actions.

In this example we will show how you can set up a CI/CD build server using GitHub Actions in Azure Web Apps.

We will not cover how you can set up the site itself as this is beyond this documentation.

The following steps will take you through setting up a build server in Azure Web Apps. Go to the Azure portal and find the empty website that we have set up and want to connect to.

  1. Go to the Deployment Center.

Azure deployments

In the Deployment Center we can set up the CI/CD build server. With this example we are going to set up our build server by using GitHub Actions. It is possible to set up the build server however you want as long as it supports executing powershell scripts.

  1. Go to the Settings tab.

  2. Choose which source and build provider to use.

    • In this case we want to choose GitHub.

Build server clean
  1. Choose the Organization which you created our GitHub repository under.

  2. Choose the repository that was set up earlier in this guide.

  3. Select which branch that we want the build server to build into.

We can see which runtime stack and version we are running, in this example we are running .NET and Version 6.0.

Once the information has been added we can go ahead and preview the YAML file that will be used for the build server:

Workflow configuration
  1. Save the workflow.

The website and the GitHub repository are now connected.

If we go back to the GitHub repository we can see that a new folder have been created called Workflows:

Workflows

Inside the folder, we find that the YAML file has been created with the default settings from the Azure Portal. The file will need to be configured so it fits into your set up.

  1. Pull down the new file and folder, so you can work with the YAML file on your local machine.

  2. Configure it to work with our Umbraco Deploy installation.

When it have been configured it will look something like this:

# Docs for the Azure Web Apps Deploy action: https://github.com/Azure/webapps-deploy
# More GitHub Actions for Azure: https://github.com/Azure/actions
name: Build and deploy ASP.Net Core app to Azure Web App - Jonathan-deploy-v10
on:
  push:
    branches:
      - main
  workflow_dispatch:
jobs:
  build:
    runs-on: windows-latest
    steps:
      - name: Checkout the git repository
        uses: actions/checkout@v3
      - name: Setup dotnet 6
        uses: actions/setup-dotnet@v2
        with:
          dotnet-version: '6.0.x'
      - name: Build with dotnet
        working-directory: 'Jonathan-Deploy-V10'
        run: dotnet build --configuration Release
      - name: Publish with dotnet
        working-directory: 'Jonathan-Deploy-V10'
        run: dotnet publish -c Release -o ${{env.DOTNET_ROOT}}/myapp
        
      - name: Upload artifact for deployment job
        uses: actions/upload-artifact@v4
        with:
          name: .net-app
          path: ${{env.DOTNET_ROOT}}/myapp
  deploy:
    runs-on: windows-latest
    needs: build
    environment:
      name: 'Production'
      url: ${{ steps.deploy-to-webapp.outputs.webapp-url }}
    env:
      deployBaseUrl: https://jonathan-testing-deploy-v10.testsite.net
      umbracoDeployReason:  DeployingMySite
    steps:
      - name: Download artifact from build job
        uses: actions/download-artifact@v4
        with:
          name: .net-app
      - name: Deploy to Azure Web App
        id: deploy-to-webapp
        uses: azure/webapps-deploy@v2
        with:
          app-name: 'Jonathan-Deploy-V10'
          slot-name: 'Production'
          publish-profile: ${{ secrets.AZUREAPPSERVICE_PUBLISHPROFILE_ABC78A5A9E9FG07F87E8R5G9H9J0J7J8 }}
          package: .
      - name:  Run Deploy Powershell - triggers deployment on remote env
        shell: powershell
        run: .\TriggerDeploy.ps1 -InformationAction:Continue -Action TriggerWithStatus -ApiKey ${{ secrets.deployApiKey }} -BaseUrl  ${{ env.deployBaseUrl }} -Reason  ${{ env.umbracoDeployReason }} -Verbose       

This is only an example of how you can set up the CI/CD pipeline for Umbraco Deploy. It is possible to set it up in a way that works for you and your preferred workflow.

We also need to add the License file and TriggerDeploy.ps1 file in an item group in the csproj file:

<ItemGroup>
<Content Include="umbraco/Licenses/umbracoDeploy.lic" CopyToOutputDirectory="Always"/>
<Content Include="TriggerDeploy.ps1" CopyToOutputDirectory="Always"/>
</ItemGroup>

As well as enabling Unattended install in the appSettings.json file so Umbraco installs automatically:

"Umbraco": {
    "CMS": {
      "Unattended": {
        "InstallUnattended": true
      }

Before the build can work, we will need to set up our generated API key to work with the build server in GitHub Actions.

  1. Open your GitHub repository.

  2. Navigate to Settings.

  3. Go to the Secrets tab.

  4. Select "New repository secret".

  5. Call the new secret "DEPLOYAPIKEY".

  6. Add the API key from the appSettings.json file.

  7. Save the secret.

We can now go ahead and commit the configured YAML file and push up all the files to the repository.

Go to GitHub where you will now be able to see that the CI/CD build has started running:

Deployment build started

The build server will go through the steps in the YAML file, and once it is done the deployment have gone through successfully:

Deployment Complete

You can now start creating content on the local machine. Once you create something like a Document Type, the changes will get picked up in Git.

When you're done making changes, commit them and deploy them to GitHub. The build server will run and extract the changes into the website in Azure.

This will only deploy the schema data for our local site to your website.

You will need to transfer content and media from the backoffice on your local project using the queue for transfer feature.

Configuration

Learn about the different settings and configurations available in Umbraco Deploy.

All configuration for Umbraco Deploy is held in the appSettings.json file found at the root of your Umbraco website. If the configuration has been customized to use another source, then the same keys and values discussed in this article can be applied there.

The convention for Umbraco configuration is to have package based options stored as a child structure below the Umbraco element, and as a sibling of CMS. Umbraco Deploy configuration follows this pattern, i.e.:

{
  ...
  "Umbraco": {
    "CMS": {
        ...
    },
    "Deploy": {
        ...
    }
  }
}

There are some required settings but most configuration for Umbraco Deploy is optional. In other words, values have defaults that will be applied if no configuration is available for a particular key.

For illustration purposes, the following structure represents the full set of options for configuration of Umbraco Deploy, along with the default values. This will help when you need to provide a different setting to understand where it should be applied.

{
  ...
  "Umbraco": {
    "Deploy": {
        "Settings": {
            "ApiKey": "<your API key here>",
            "Edition": "Default",
            "ExcludedEntityTypes": [],
            "RelationTypes" : [],
            "ValueConnectors": [],
            "SessionTimeout": "0.0:20:00",
            "SourceDeployTimeout": "0.0:20:00",
            "DatabaseCommandTimeout": "0.0:20:00",
            "EnableSignatureCacheReads": true,
            "HttpClientTimeout": "0.0:20:00",
            "DiskOperationsTimeout": "0.0:05:00",
            "SourceDeployBatchSize": null,
            "PackageBatchSize": null,
            "UseDatabaseTransferQueue": true,
            "IgnoreBrokenDependenciesBehavior": "Restore",
            "AcceptInvalidCertificates": false,
            "TransferFormsAsContent": true,
            "TransferDictionaryAsContent": false,
            "SetEmptyDictionaryItemsOnTransfer": true,
            "IgnoreMissingLanguagesForDictionaryItems": false,
            "AllowMembersDeploymentOperations": "None",
            "TransferMemberGroupsAsContent": false,
            "ExportMemberGroups": true,
            "ReloadMemoryCacheFollowingDiskReadOperation": false,
            "AllowDomainsDeploymentOperations": "None",
            "AllowPublicAccessDeploymentOperations": "AddOrUpdate",
            "TrashedContentDeploymentOperations": "Import",
            "PreferLocalDbConnectionString": false,
            "NumberOfSignaturesToUseAllRelationCache": 100,
            "ContinueOnMediaFilePathTooLongException": false,
            "SuppressCacheRefresherNotifications": false,
            "ResolveUserInTargetEnvironment": false
        }
    }
  }
}

ApiKey

The API key is a 10 character random string applied with the same value to all environments in order to authenticate HTTP requests between them.

Edition

The default value for this setting is Default, which configures Umbraco Deploy to work according to how we expect most customers to use the product. Umbraco schema, such as Document and Data Types, are serialized to disk as .uda files in save operations. These are checked into source control and used to update the schema in the upstream environments via a trigger from your CI/CD pipeline, or automatically if using Umbraco Cloud.

Items managed by editors - content, media and optionally forms, dictionary items and members - are deployed between environments using the transfer and restore options available in the backoffice.

It is possible to use this method for all Umbraco data, by setting the value of this setting to BackOfficeOnly. With this in place, all data, including what is typically considered as schema, are available for transfer via the backoffice.

Our recommended approach is to leave this setting as Default and use source control and a deployment pipeline to ensure that structural changes to Umbraco are always aligned with the code and template amends that use them.

However, we are aware that some customers prefer the option to use the backoffice for all data transfers. If that is the case, the BackOfficeOnly setting will allow this.

ExcludedEntityTypes

This setting allows you to exclude a certain type of entity from being deployed. This is not recommended to set, but sometimes there may be issues with the way a custom media fileprovider works with your site and you will need to set it for media files. Here is an example:

"ExcludedEntityTypes": ["media-file"],

RelationTypes

This setting allows you to manage how relations are deployed between environments. You will need to specify an alias and a mode for each relationtype. The mode can be either:

  • Exclude - This causes the relation to be excluded and not transferred on deployments.

  • Weak - This causes the relation to be deployed if both content items are found on the target environment.

  • Strong - This requires the content item that is related is set as a dependency, so if anything is added as a relation it would also add it as a dependency.

"RelationTypes": [
    {
        "Alias": "relateParentDocumentOnDelete",
        "Mode": "Weak",
    },
    {
        "Alias": "relateShopItemOnCreate",
        "Mode": "Exclude",
    }
],

ValueConnectors

This setting is used by package creators who wants their custom editors to work with Deploy. The packages should be creating this setting automatically. There is a community driven package that has value connectors for Deploy called Deploy Contrib.

Here is an example of how the setting can look:

"ValueConnectors": [
    {
        "Alias": "nuPickers.DotNetCheckBoxPicker",
        "TypeName": "Umbraco.Deploy.Contrib.Connectors.ValueConnectors.NuPickersValueConnector,Umbraco.Deploy.Contrib.Connectors",
    }
],

Timeout settings

Umbraco Deploy have a few built-in timeouts, which on larger sites might need to be modified. You will usually see these timeouts in the backoffice with an exception mentioning a timeout. It will be as part of a full restore or a full deploy of an entire site. In the normal workflow you should never hit these timeouts.

There are four settings available relating to backoffice deployment operations:

  • SessionTimeout

  • SourceDeployTimeout

  • HttpClientTimeout

  • DatabaseCommandTimeout

These timeout settings default to 20 minutes, but if you are transferring a lot of data you may need to increase it.

It's important that these settings are added to both the source and target environments in order to work.

A fifth timeout setting is available from Umbraco Deploy 9.5 and 10.1, allowing for the adjustment of the maximum time allowed for disk operations such as schema updates.

  • DiskOperationsTimeout

This setting defaults to 5 minutes.

All of these times are configured using standard timespan format strings. The values of the settings will have to be the same value on all timeout settings.

Batch settings

Even with appropriate settings of the above timeouts, Deploy's backoffice transfer operations can hit a hard limit imposed by the hosting environment. For Azure, this is around 4 minutes. This will typically only be reached if deploying a considerable amount of items in one go. For example, a media folder with thousands of items can reach this limit.

An error message of "The remote API has returned a response indicating a platform timeout" will be reported.

If encountering this issue, there are two batch settings that can be applied with integer values (for example 500). This will cause Deploy to transfer items in batches, up to a maximum size. This will allow each individual batch to complete within the time available. The higher the value, the bigger the batches.

  • SourceDeployBatchSize - applies a batch setting for the transfer of multiple selected items to an upstream environment (such as a media folder with many images).

  • PackageBatchSize - applies a batch setting to the processing of a Deploy "package", which contains all the items selected for a Deploy operation, plus all the determined dependencies and relations.

UseDatabaseTransferQueue

In earlier versions of Umbraco Deploy, the transfer queue was implemented using in-memory storage. As a result, it would not be persisted across application restarts.

From 9.5 and 10.1, a database backed queue was implemented and is used by default.

If for any reason there was a need to revert to the previous implementation, the value of this setting can be set to false.

TransferFormsAsContent

In order for Deploy to handle Forms data as content, you'll to ensure the TransferFormsAsContent setting is set to true. To transfer Forms data as schema, i.e. via .uda files committed to source control, use a value of false.

On changing this value from false to true, make sure to remove any .uda files for Forms entities that have already been serialized to disk. These will no longer be updated. By deleting them you avoid any risk of them being processed in the future and inadvertently reverting a form to an earlier state.

TransferDictionaryAsContent

In a similar way, Deploy can be configured to allow for backoffice transfers of dictionary items instead of using files serialized to disk, by setting TransferDictionaryAsContent as true.

Please see the note above under TransferFormsAsContent on the topic of removing any existing serialized files having changed this value to true.

IgnoreMissingLanguagesForDictionaryItems

When deploying dictionary items, an exception will be thrown if a translation is provided for a language that doesn't exist in the target environment.

Normally this is a useful fail-safe to ensure translations aren't lost in the transfer operation.

If you have deleted languages that have already existing translations, you may want to temporarily remove this check. You can do that by setting this value to true.

When this is in place a translation for a language that doesn't exist in the target environment will be ignored. A warning message will be output to the log.

SetEmptyDictionaryItemsOnTransfer

When deploying dictionary items, Umbraco Deploy follows the approach used for all content, emptying values that are transferred and set.

If you transfer a dictionary item with an empty translation to another environment that already contains a translation, it will be overwritten.

Set this value to false to not overwrite already populated values with empty strings.

AllowMembersDeploymentOperations and TransferMemberGroupsAsContent

As of version 9.3.0, it's also possible to transfer members and member groups via the back-office between environments. This is disabled by default as a deliberate decision to make use of the feature needs to be taken, as for most installations it will make sense to have member data created and managed only in production. There are obvious potential privacy concerns to consider too. However, if being able to deploy and restore this information between environments makes sense for the specific workflow of your project, it's a supported scenario.

To enable, you can add or amend the AllowMembersDeploymentOperations and TransferMemberGroupsAsContent settings.

The AllowMembersDeploymentOperations setting can take four values:

  • None - member deployment operations are not enabled (the default value if the setting is missing)

  • Restore - restore of members from upstream environments via the backoffice is enabled

  • Transfer - transfer of members to upstream environments via the backoffice is enabled

  • All - restore and transfer of members from upstream environments via the backoffice is enabled

With TransferMemberGroupsAsContent set to true, member groups can also be transferred via the backoffice, and groups identified as dependencies of members being transferred will be automatically deployed.

Please see the note above under TransferFormsAsContent on the topic of removing any existing serialized files having changed this value to true.

ExportMemberGroups

This setting is to be defined and set to false only if you are using an external membership provider for your members. You will not want to export Member Groups that would no longer be managed by Umbraco but by an external membership provider.

Setting exportMemberGroups to false will no longer export Member Groups to .uda files on disk. The default for this setting is true, as most sites use Umbraco's built-in membership provider and thus will want the membership groups exported.

IgnoreBrokenDependenciesBehavior

When restoring or transferring content, Umbraco Deploy will make checks to ensure that any dependent content, media or other items are either present in the target environment, or can be deployed from the source environment.

For example, you may have a media picker on a content item, referencing media that has been deleted or is in the recycle bin. In this situation the dependency won't be available in the target environment.

Deploy can halt at this point, so you get an error and the deployment won't complete until the issue is resolved. To fix, you would need to remove the reference to the deleted media item.

Alternatively, you can configure Deploy to ignore these issues and proceed with the transfer operation without warning.

To configure the behavior you prefer, amend this value to either None, Transfer, Restore or All.

For example, using the following settings, you will have an installation that ignores broken dependencies when restoring from an upstream environment. It will however still prevent deployment and report any dependency issues when attempting a transfer to an upstream environment.

    "IgnoreBrokenDependenciesBehavior": "Restore",

When configuring for Deploy 9, an additional IgnoreBrokenDependencies setting existed that took a value of true or false. To achieve the same result as the example above, the following configuration was required:

    "IgnoreBrokenDependencies": true,
    "IgnoreBrokenDependenciesBehavior": "Restore",

Memory cache reload

Some customers have reported intermittent issues related to Umbraco's memory cache following deployments, which are resolved by a manual reload of the cache via the Settings > Published Status > Caches dashboard. If you are running into such issues and are able to accommodate a cache clear after deployment, this workaround can be automated via the following setting:

    "ReloadMemoryCacheFollowingDiskReadOperation": true,

By upgrading to the most recent available version of the CMS major you are running, you'll be able to benefit from the latest bug fixes and optimizations in this area. That should be your first option if encountering cache related issues. Failing that, or if a CMS upgrade is not an option, then this workaround can be considered.

Deployment of culture & hostnames settings

Culture and hostname settings, defined per content item for culture invariant content, are not deployed between environments by default. They can be opted into via configuration.

    "AllowDomainsDeploymentOperations": "None|Culture|AbsolutePath|Hostname|All",

To enable this, set the configuration value as appropriate for the types of domains you want to allow:

  • Culture - the language setting for the content, defined under "Culture"

  • AbsolutePath - values defined under "Domains" with an absolute path, e.g. "/en"

  • Hostname - values defined under "Domains" with a full host name, e.g. "en.mysite.com"

Combinations of settings can be applied, e.g. Hostname,AbsolutePath.

Deployment of public access settings

When deploying content items, public access rules based on member groups are transferred. You can amend this behavior using this setting.

    "AllowPublicAccessDeploymentOperations": "None|AddOrUpdate|Remove|All",
  • None - no public access rules will be transferred

  • AddOrUpdate - public access rules added or updated in a source environment will be transferred to the destination

  • Remove - public access rules removed a source environment will be removed in the destination

  • All - all public access information will be transferred

AddOrUpdate is the default setting used if no value is configured.

Deployment of trashed content

Specifies options for handling trashed content (documents, media and members) on export or import:

"TrashedContentDeploymentOperations": "None|Export|Import|All"

You can amend this behavior using this setting:

  • None - trashed content will not be exported or imported

  • Export - trashed content will be included in an export

  • Import - trashed content will be processed and moved to the recycle bin on import

  • All - trashed content will be included in an export, processed and moved to the recycle bin on import

PreferLocalDbConnectionString

When using Umbraco Deploy with Umbraco Cloud, a development database is automatically created when restoring a project into a local environment for the first time.

For Umbraco 10, by default, a SQLite database is created.

If you would prefer to use SQL Server LocalDb when it's available on your local machine, set this value to true. If LocalDB isn't reported as being available by Umbraco, it will fallback to using a SQLite database instead.

"PreferLocalDbConnectionString": true

MediaFileChecksumCalculationMethod

Deploy will do comparisons between the entities in different environments to determine if they match and decide whether to include them in the operation. By default, for media files, a check is made on a portion of the initial bytes of the file.

This corresponds to the default setting of PartialFileContents.

If a lot of files need to be checked, this can be slow, and a faster option is available that uses the file metadata. The only downside of changing this option is a marginally increased chance of Deploy considering a media file hasn't changed when it has. This would omit it from the deployment.

To use this method, set the value to Metadata.

NumberOfSignaturesToUseAllRelationCache

When reviewing a set of items for a deployment operation, Deploy will retrieve and include relations. It does this either via single database lookups, or by bringing all relations into memory in one step, and retrieving them from there.

For small deployment operations, the former is the more optimal approach. It gets slow though when the number of items being transferred is large.

The cut-off before switching methods is set by this configuration value, and it defaults to an operation size of 100 items.

SuppressCacheRefresherNotifications

When a Deploy operation completes, cache refresher notifications are fired. These are used to update Umbraco's cache and search index.

In production this setting shouldn't be changed from it's default value of false, to ensure these additional data stores are kept up to date.

If attempting a one-off, large transfer operation, before a site is live, you could set this value to true. That would omit the firing and handling of these notifications and remove their performance overhead. Following which you would need to ensure to rebuild the cache and search index manually via the backoffice Settings dashboards.

ResolveUserInTargetEnvironment

With this setting assigned a value of true, Umbraco Deploy will attempt to resolve users when transfers are made to new environments.

Users and user groups are maintained separately in different environments, so it isn't always the case that an editor has accounts across all environments. When an account exists matching by email address, Deploy will associate the changes made in upstream environments with the user that initiated the transfer. Allowing the expected information about save and publish operations to be available in the audit log of the environment where the data was transferred.

When the setting is set to false, or a matching account isn't found, the audit records will be associated with the super-user administrator account.

Partial Restores

How to partially restore content in Umbraco Deploy

In some cases you might not want to restore the entire content tree, but only the parts that you need. Partial restores is a feature that allows for restoring specific parts of your content instead of restoring everything.

You can use Partial Restore on

  • Environments with existing content or media, and on

  • Empty environments

Empty environment

In this scenario you've cloned down your environment to your local machine or setup a new environment. In both cases the new environment will have an empty Content section as well as an empty Media section.

Be aware that this feature will also restore all dependencies on the selected content.

E.g. when you restore a content node which references media items as well as other content nodes, these will all be restored as well, including any parent nodes that these nodes depend on.

Follow these steps to perform a partial restore to get only the parts you need:

  1. Go to the Content section of the Umbraco backoffice on your environment or locally.

  2. Right-click the Content Tree, or click the three dots an select Do something else.

  3. Choose Partial Restore.

  4. Select the environment that you would like to restore content from.

  5. Click "Select content to restore" - this will open a dialog with a preview of the content tree from the environment you selected.

  6. Select the content node you would like to restore.

  7. Decide whether you also want to restore any child nodes below the selected node.

  8. Start the restore by clicking Restore.

  9. To see the restored content, reload the content tree - right-click the Content tree to find this option.

Keep in mind if you select a content node deeper down the tree, all the parents above it, required for the node to exist, will be restored as well.

Partial restore on empty environment

Partial Restores on empty environments are especially helpful when you have a large amount of content and media and do not necessarily need it all for the task you need to do.

Instead of having to restore everything which could potentially take a long time, doing a partial restore can be used to shorten the waiting time by only restoring the parts you need. This will ensure that you can quickly get on your way with the task at hand.

Environment with existing content or media

It is also possible to use the Partial Restore feature on environments where you already have content in the Content tree.

Imagine that you are working with your Umbraco project locally. One of your content editors updates a section in the content tree on the production environment. You would like to see how this updated content looks with the new code you are working on. Follow these steps to do a Partial Restore of the updated content node:

  1. Go to the Content section of your local Umbraco backoffice

  2. Right-click the content node which you know contains updates

  3. Choose Partial Restore

  4. Select the environment that you would like to restore content from

  5. Decide whether you also want restore any child nodes under the selected node

  6. Start the restore by clicking Restore

  7. When the restore is done, reload the content tree to see the changes

Partial restore

Handling Cache Refresher Notifications

How to respond to deployment events using cache refresher notifications

Background

When you deploy content or other Umbraco data between environments, some notifications that are normally fired in CMS operations are suppressed.

For example, you may handle a ContentPublishedNotification to apply some custom logic when a content item is published. This code will run in a normal CMS publish operation. However, when deploying a content item into another environment and triggering it's publishing there, the notification will not be issued. And the custom logic in the notification handler will not run.

This behavior is deliberate and done for performance and reliability reasons. A normal save and publish operation by an editor operates on one item at a time. With deployments, we may have many, and publishing these notifications may lead to at best slow operations, and at worst inconsistent data.

The notification will also already be published on the environment where the actual operation was carried out. So repeating this with each content transfer might also result in unwanted behavior.

However, what if you do want to run some code on an update, even if this is happening as part of a Deploy operation?

Not all notifications are suppressed by Umbraco Deploy. Some are batched and fired after the deploy operation is complete. These include those related to refreshing the Umbraco cache and rebuilding indexes.

You can use these cache refresher notifications to handle operations that should occur after a deployment is completed. All notification issued by the CMS are made available. So when deploying a set of content items, a refresher notification will be issued for each.

Implementing a Cache Refresher Notification

The following two code samples illustrate how this can be done.

The first handles a content cache refresher, which takes a payload from where the content ID can be extracted. Using that the content can be retrieved in the local Umbraco instance and used as appropriate.

For more details and further examples, please see the .

The second example is similar, but handles an update to a dictionary item. With this one we get a parameter that consists of the item's ID. Again we can retrieve it and carry out some further processing.

In both cases, as is usual for notification handlers, you will need to register them via a composer:

using Umbraco.Cms.Core.Cache;
using Umbraco.Cms.Core.Events;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Notifications;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Sync;

namespace TestSite.Business.NotificationHandlers;

public class ContentCacheRefresherNotificationHandler : INotificationHandler<ContentCacheRefresherNotification>
{
    private readonly ILogger<ContentCacheRefresherNotificationHandler> _logger;
    private readonly IContentService _contentService;

    public ContentCacheRefresherNotificationHandler(
        ILogger<ContentCacheRefresherNotificationHandler> logger,
        IContentService contentService)
    {
        _logger = logger;
        _contentService = contentService;
    }

    public void Handle(ContentCacheRefresherNotification notification)
    {
        // We only want to handle the RefreshByPayload message type.
        if (notification.MessageType != MessageType.RefreshByPayload)
        {
            return;
        }

        // Cast the payload to the expected type.
        var payload = (ContentCacheRefresher.JsonPayload[])notification.MessageObject;

        // Handle each content item in the payload.
        foreach (ContentCacheRefresher.JsonPayload item in payload)
        {
            // Retrieve the content item.
            var contentItemId = item.Id;
            IContent? contentItem = _contentService.GetById(contentItemId);
            if (contentItem is null)
            {
                _logger.LogWarning(
                    "ContentCacheRefresherNotification handled for type {MessageType} but content item with Id {Id} could not be found.",
                    notification.MessageType,
                    contentItemId);
                return;
            }

            // Do something with the content item. Here we'll just log some details.
            _logger.LogInformation(
                "ContentCacheRefresherNotification handled for type {MessageType} and id {Id}. " +
                "Key: {Key}, Name: {Name}",
                notification.MessageType,
                contentItemId,
                contentItem.Key,
                contentItem.Name);
        }
    }
}
using Umbraco.Cms.Core.Events;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Notifications;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Sync;

namespace TestSite.Business.NotificationHandlers;

public class DictionaryCacheRefresherNotificationHandler : INotificationHandler<DictionaryCacheRefresherNotification>
{
    private readonly ILogger<DictionaryCacheRefresherNotificationHandler> _logger;
    private readonly ILocalizationService _localizationService;

    public DictionaryCacheRefresherNotificationHandler(
        ILogger<DictionaryCacheRefresherNotificationHandler> logger,
        ILocalizationService localizationService)
    {
        _logger = logger;
        _localizationService = localizationService;
    }

    public void Handle(DictionaryCacheRefresherNotification notification)
    {
        // We only want to handle the RefreshById message type.
        if (notification.MessageType != MessageType.RefreshById)
        {
            return;
        }

        // Retrieve the dictionary item.
        var dictionaryItemId = (int)notification.MessageObject;
        IDictionaryItem? dictionaryItem = _localizationService.GetDictionaryItemById(dictionaryItemId);
        if (dictionaryItem is null)
        {
            _logger.LogWarning(
                "DictionaryCacheRefresherNotification handled for type {MessageType} but dictionary item with Id {Id} could not be found.",
                notification.MessageType,
                dictionaryItemId);
            return;
        }

        // Do something with the dictionary item. Here we'll just log some details.
        _logger.LogInformation(
            "DictionaryCacheRefresherNotification handled for type {MessageType} and id {Id}. " +
            "Key: {Key}, Default Value: {DefaultValue}",
            notification.MessageType,
            dictionaryItemId,
            dictionaryItem.ItemKey,
            dictionaryItem.GetDefaultValue());
    }
}
using Umbraco.Cms.Core.Composing;
using Umbraco.Cms.Core.Notifications;
using TestSite.Business.NotificationHandlers;

namespace TestSite.Business;

public class SiteComposer : IComposer
{
    public void Compose(IUmbracoBuilder builder)
    {
        builder.AddNotificationHandler<ContentCacheRefresherNotification, ContentCacheRefresherNotificationHandler>();
        builder.AddNotificationHandler<DictionaryCacheRefresherNotification, DictionaryCacheRefresherNotificationHandler>();
    }
}
CMS Cache Refresher Notifications documentation
Umbraco Deploy Overview
Umbraco Deploy - Content transfer and deploy
Umbraco Deploy - Content transfer and restore

Import and Export

How to import and export content and schema between Umbraco environments and projects

What is import and export?

The import and export feature of Umbraco Deploy allows you to transfer content and schema between Umbraco environments. Exports are made from one environment to a .zip file. And this file is imported into another environment to update the Umbraco data there.

When to use import and export

Umbraco Deploy provides two primary workflows for managing different types of Umbraco data:

  • Umbraco schema (such as document types and data types) are transferred as .uda files serialized to disk. They are deployed to refresh the schema information in a destination environment along with code and template updates.

  • Umbraco content (such as content and media) are transferred by editors using backoffice operations.

We recommend using these approaches for day-to-day editorial and developer activities.

Import and export is intended more for larger transfer options, project upgrades, or one-off tasks when setting up new environments.

As import and export is a two-step process, it doesn't require inter-environment communication. This allows us to process much larger batches of information without running into hard limits imposed by Cloud hosting platforms.

We are also able provide hooks to allow for migrations of artifacts (such as data types) and property data when importing. This should allow you to migrate your Umbraco data from one Umbraco major version to a newer one.

Exporting content and schema

To export content and schema, you can select either a specific item of content, or a whole tree or workspace.

When exporting, you can choose to include associated media files. Bear in mind that including media files for a large site can lead to a big zip file. So even with this option, you might want to consider a different method for transferring large amounts of media. For example using direct transfer between Cloud storage accounts or File Transfer Protocol (FTP).

If your account has access to the Settings section, you can also choose to include the schema information and related files as well.

Export dialog

Umbraco Deploy will then serialize all the selected items to individual files, archive them into a zip file and make that available for download. You can download the file using the Download button.

After the download, you should also delete the archive file from the server. You can do this immediately via the Delete button available in the dialog.

Export dialog complete

If you miss doing this, you can also clean up archive files from the Umbraco Deploy dashboard in the Settings section.

Delete exports

The exported archive files are saved to the Umbraco temp folder in the Deploy\Export sub-directory. This is a temporary (non-persistent) location, local to the backoffice server and therefore shouldn't be used for long-term storage of exports. You can also only download the file from the export dialog in the backoffice.

Importing content and schema

Having previously exported content and schema to a zip file, you can import this into a new environment.

Import dialog

You can upload the file via the browser.

Similar to when exporting, you can choose to import everything from the archive file, or only content, schema or files.

Deploy does not touch the default maximum upload size, but can you configure this yourself by following the CMS documentation.

Import dialog step 2

We validate the file before importing. Schema items that content depends on must either be in the upload itself or already exist on the target environment with the same details. If there are any issues that mean the import cannot proceed, it will be reported. You may also be given warnings for review. You can choose to ignore these and proceed if they aren't relevant to the action you are carrying out.

The import then proceeds, processing all the items provided in the zip file.

Import dialog step 3

Once complete or on close of the dialog, the imported file will be deleted from the server. If this is missed, perhaps via a closed browser, you can also delete archive files from the Umbraco Deploy dashboard in the Settings section.

Migrating whilst importing

As well as importing the content and schema directly, we also provide support for modifying the items as part of the process.

For example, you may have taken an export from an Umbraco 8 site, and are looking to import it into a newer major version. In this situation, most content and schema will carry over without issue. However, you may have some items that are no longer compatible. Usually this is due to a property editor - either a built-in Umbraco one or one provided by a package. These may no longer be available in the new version.

Often though there is a similar replacement. Using Deploy's import feature we can transform the exported content for the obsolete property into that used by the new one during the import. The migration to a content set compatible with the new versions can then be completed.

For example, we can migrate from a Nested Content property in Umbraco 8 to a Block List in Umbraco 10.

We provide the necessary migration hooks for this to happen, divided into two types - artifact migrators and property migrators.

Artifact migrators

Artifact migrators work by transforming the serialized artifact of any imported artifact, via two interfaces:

  • IArtifactMigrator - where the migration occurs at the artifact property level

  • IArtifactJsonMigrator - where the migration occurs at the lower level of transforming the serialized JSON itself.

Implementations to handle common migrations of data types from obsoleted property editors are available:

  • ReplaceMediaPickerDataTypeArtifactMigrator - migrates a datatype from using the legacy media picker to the current version of this property editor

  • ReplaceNestedContentDataTypeArtifactMigrator - migrated from a datatype based on the obsolete nested content property editor to the block list.

We've also made available base implementations that you can use to build your own migrations. You may have a need to handle transfer of information between other obsolete and replacement property editors that you have in your Umbraco application.

  • ArtifactMigratorBase<TArtifact> - migrates the artifact of the specified type

  • DataTypeArtifactMigratorBase - migrates data type artifacts

  • ReplaceDataTypeArtifactMigratorBase - migrates a data type from one property editor to another

  • ArtifactJsonMigratorBase<TArtifact> - migrates the JSON of the specified artifact type

Property migrators

Property migrators work to transform the content property data itself. They are used in the Deploy content connectors (documents, media and members) when the property editor is changed during an import:

Again we have an interface:

  • IPropertyTypeMigrator

Implementations for common migrations:

  • MediaPickerPropertyTypeMigrator

  • NestedContentPropertyTypeMigrator

And a base type to help you build your own migrations:

  • PropertyTypeMigratorBase

Determining whether the property editor has changed is done by comparing the PropertyEditorAliases dictionary (containing editor aliases for each content property) stored in the content artifact to the current content type/data type configuration.

Registering migrators

Migrators will run if you've registered them to, hence you can enable only the ones needed for your solution.

You can do this via a composer, as in the following example. Here we register two of the migrators shipped with Umbraco Deploy:

using Umbraco.Cms.Core.Composing;
using Umbraco.Deploy.Core.Migrators;
using Umbraco.Deploy.Infrastructure.Migrators;

internal class ArtifactMigratorsComposer : IComposer
{
    public void Compose(IUmbracoBuilder builder)
    {
        builder.DeployArtifactMigrators()
            .Append<ReplaceNestedContentDataTypeArtifactMigrator>()
            .Append<ReplaceMediaPickerDataTypeArtifactMigrator>();

        builder.DeployPropertyTypeMigrators()
            .Append<NestedContentPropertyTypeMigrator>()
            .Append<MediaPickerPropertyTypeMigrator>();
    }
}

A custom migration example - Nested Content to Block List

In order to help writing your own migrations, we share here the source code of an example that ships with Umbraco Deploy. This migration converts Nested Content to Block List.

First we have the artifact migrator that handles the conversion of the configuration stored with a datatype:

ReplaceNestedContentDataTypeArtifactMigrator.cs (migrate Nested Content data type to Block List)
using System.Globalization;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.PropertyEditors;
using Umbraco.Cms.Core.Serialization;
using Umbraco.Cms.Core.Services;
using Umbraco.Deploy.Infrastructure.Artifacts;

public class ReplaceNestedContentDataTypeArtifactMigrator : ReplaceDataTypeArtifactMigratorBase<NestedContentConfiguration, BlockListConfiguration>
{
    private readonly IContentTypeService _contentTypeService;

    public ReplaceNestedContentDataTypeArtifactMigrator(PropertyEditorCollection propertyEditors, IConfigurationEditorJsonSerializer configurationEditorJsonSerializer, IContentTypeService contentTypeService)
        : base(Constants.PropertyEditors.Aliases.NestedContent, Constants.PropertyEditors.Aliases.BlockList, propertyEditors, configurationEditorJsonSerializer)
        => _contentTypeService = contentTypeService;

    protected override BlockListConfiguration? MigrateConfiguration(NestedContentConfiguration configuration)
    {
        var blockListConfiguration = new BlockListConfiguration()
        {
            UseInlineEditingAsDefault = true // Similar to how Nested Content looks/works
        };

        if (configuration.MinItems > 0)
        {
            blockListConfiguration.ValidationLimit.Min = configuration.MinItems;
        }

        if (configuration.MaxItems > 0)
        {
            blockListConfiguration.ValidationLimit.Max = configuration.MaxItems;
        }

        if (configuration.ContentTypes is not null)
        {
            var blocks = new List<BlockListConfiguration.BlockConfiguration>();
            foreach (NestedContentConfiguration.ContentType nestedContentType in configuration.ContentTypes)
            {
                if (nestedContentType.Alias is not null &&
                    GetContentTypeKey(nestedContentType.Alias) is Guid contentTypeKey)
                {
                    blocks.Add(new BlockListConfiguration.BlockConfiguration()
                    {
                        Label = nestedContentType.Template,
                        ContentElementTypeKey = contentTypeKey
                    });
                }
            }

            blockListConfiguration.Blocks = blocks.ToArray();
        }

        if (blockListConfiguration.ValidationLimit.Min == 1 &&
            blockListConfiguration.ValidationLimit.Max == 1 &&
            blockListConfiguration.Blocks.Length == 1)
        {
            blockListConfiguration.UseSingleBlockMode = true;
        }

        return blockListConfiguration;
    }

    protected virtual Guid? GetContentTypeKey(string alias)
    {
        if (_contentTypeService.Get(alias) is IContentType contentTypeByAlias)
        {
            return contentTypeByAlias.Key;
        }

        // New content types are initially saved by Deploy with a custom postfix (to avoid duplicate aliases), so try to get the first matching item
        string aliasPrefix = alias + "__";
        foreach (IContentType contentType in _contentTypeService.GetAll())
        {
            if (contentType.Alias.StartsWith(aliasPrefix) &&
                int.TryParse(contentType.Alias[aliasPrefix.Length..], NumberStyles.HexNumber, null, out _))
            {
                return contentType.Key;
            }
        }

        return null;
    }
}

And secondly we have the property migrator that handles restructuring the content property data:

NestedContentPropertyTypeMigrator.cs (migrate Nested Content property data to Block List)
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Deploy;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.Blocks;
using Umbraco.Cms.Core.Services;
using Umbraco.Deploy.Core;
using Umbraco.Deploy.Core.Migrators;
using Umbraco.Deploy.Infrastructure.Extensions;

public class NestedContentPropertyTypeMigrator : PropertyTypeMigratorBase
{
    private readonly ILogger<NestedContentPropertyTypeMigrator> _logger;
    private readonly IContentTypeService _contentTypeService;

    public NestedContentPropertyTypeMigrator(ILogger<NestedContentPropertyTypeMigrator> logger, IContentTypeService contentTypeService)
        : base(Constants.PropertyEditors.Aliases.NestedContent, Constants.PropertyEditors.Aliases.BlockList)
    {
        _logger = logger;
        _contentTypeService = contentTypeService;
    }

    public override object? Migrate(IPropertyType propertyType, object? value, IDictionary<string, string> propertyEditorAliases, IContextCache contextCache)
    {
        if (value is not string stringValue || !stringValue.TryParseJson(out NestedContentItem[]? nestedContentItems) || nestedContentItems is null)
        {
            if (value is not null)
            {
                _logger.LogWarning("Skipping migration of Nested Content items ({PropertyTypeAlias}), because value could not be parsed: {Value}.", propertyType.Alias, value);
            }

            return null;
        }

        var layoutItems = new List<BlockListLayoutItem>();
        var contentData = new List<BlockItemData>();

        foreach (NestedContentItem nestedContentItem in nestedContentItems)
        {
            IContentType? contentType = contextCache.GetContentTypeByAlias(_contentTypeService, nestedContentItem.ContentTypeAlias);
            if (contentType is null)
            {
                _logger.LogWarning("Skipping migration of Nested Content item ({Id}), because content type does not exist: {ContentTypeAlias}.", nestedContentItem.Id, nestedContentItem.ContentTypeAlias);
                continue;
            }

            var udi = new GuidUdi(Constants.UdiEntityType.Element, nestedContentItem.Id);

            layoutItems.Add(new BlockListLayoutItem()
            {
                ContentUdi = udi
            });

            contentData.Add(new BlockItemData()
            {
                Udi = udi,
                ContentTypeKey = contentType.Key,
                RawPropertyValues = nestedContentItem.RawPropertyValues
            });
        }

        var blockValue = new BlockValue()
        {
            Layout = new Dictionary<string, JToken>()
            {
                { Constants.PropertyEditors.Aliases.BlockList, JToken.FromObject(layoutItems) }
            },
            ContentData = contentData
        };

        return JsonConvert.SerializeObject(blockValue, Formatting.None);
    }

    internal class NestedContentItem
    {
        [JsonProperty("key")]
        public Guid Id { get; set; } = Guid.NewGuid(); // Ensure a unique key is set, even if the JSON doesn't have one

        [JsonProperty("name")]
        public string? Name { get; set; }

        [JsonIgnore]
        public object? PropType { get; set; } // Ensure this property is ignored

        [JsonProperty("ncContentTypeAlias")]
        public string ContentTypeAlias { get; set; } = null!;

        [JsonExtensionData]
        public Dictionary<string, object?> RawPropertyValues { get; set; } = null!;
    }
}

Moving forward, other migrators may be built by HQ or the community for property editors found in community packages. We'll make them available for use and review via the Umbraco.Deploy.Contrib package.

Migrating from Umbraco 7

The import and export feature is available from Deploy 4.9 (which supports Umbraco 8), 10.3, 12.1 and 13.0. It's not been ported back to Umbraco 7, hence you can't trigger an export from there in the same way.

We are still able to use this feature though to help the migration from Umbraco 7 to a more recent major version using additional logic added to the Deploy Contrib project.

Exporting Umbraco 7 content and schema

We can generate an export archive in the same format as used by the content import/export feature by adding the Umbraco.Deploy.Contrib.Export assembly to your Umbraco 7 project. This archive can then be imported into a newer Umbraco version by configuring the legacy import migrators. You can also apply additional migrators to update obsolete data types and property data into newer equivalents.

This is possible via code, by temporarily applying a composer to an Umbraco 7 project to generate the export archive on start-up:

DeployExportApplicationHandler.cs (export Umbraco 7 content and schema to ZIP archive)
using System;
using System.Linq;
using System.Web.Hosting;
using Umbraco.Core;
using Umbraco.Deploy;
using UmbracoDeploy.Contrib.Export;

public class DeployExportApplicationHandler : ApplicationEventHandler
{
    protected override void ApplicationInitialized(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
    {
        // Set a default value connector that doesn't use object type prefixes
        DefaultValueConnector.SetDefault();

        // Run export after Deploy has started
        DeployComponent.Started += (sender, e) => DeployStarted();
    }

    protected void DeployStarted()
    {
        var udis = new[]
        {
            // Export all content
            Constants.UdiEntityType.Document,
            Constants.UdiEntityType.DocumentBlueprint,
            Constants.UdiEntityType.Media,
            // Export all forms data
            Constants.UdiEntityType.FormsForm,
            Constants.UdiEntityType.FormsDataSource,
            Constants.UdiEntityType.FormsPreValue
        }.Select(Udi.Create);

        var dependencyEntityTypes = new[]
        {
            // Include all related schema
            Constants.UdiEntityType.DataType,
            Constants.UdiEntityType.DataTypeContainer,
            Constants.UdiEntityType.DocumentType,
            Constants.UdiEntityType.DocumentTypeContainer,
            Constants.UdiEntityType.MediaType,
            Constants.UdiEntityType.MediaTypeContainer,
            Constants.UdiEntityType.MemberType,
            Constants.UdiEntityType.MemberGroup,
            Constants.UdiEntityType.Macro,
            Constants.UdiEntityType.DictionaryItem,
            Constants.UdiEntityType.Template,
            Constants.UdiEntityType.Language,
            // Include all related files
            Constants.UdiEntityType.MediaFile,
            Constants.UdiEntityType.MacroScript,
            Constants.UdiEntityType.PartialView,
            Constants.UdiEntityType.PartialViewMacro,
            Constants.UdiEntityType.Script,
            Constants.UdiEntityType.Stylesheet,
            Constants.UdiEntityType.UserControl,
            Constants.UdiEntityType.TemplateFile,
            Constants.UdiEntityType.Xslt
        };

        // Create export
        var zipArchiveFilePath = HostingEnvironment.MapPath("~/data/" + "export-" + Guid.NewGuid() + ".zip");
        ArtifactExportService.ExportArtifacts(udis, Constants.DeploySelector.ThisAndDescendants, zipArchiveFilePath, dependencyEntityTypes);
    }
}

Importing Umbraco 7 content and schema

To import this archive into a newer Umbraco project, you need to install UmbracoDeploy.Contrib 4.3 (for Umbraco 8) or Umbraco.Deploy.Contrib 10.2, 12.1 or 13.1 (or later) and configure the legacy artifact type resolver and migrators. Artifact type resolvers allow resolving changes in the type that's stored in the __type JSON property of the artifact, in case it moved to a different assembly or namespace (or got renamed) in a newer version. The legacy migrators handle the following changes:

  • Moving the pre-values of data types to the configuration property;

  • Moving the invariant release and expire dates of content to the (culture variant) schedule property;

  • Moving the 'allowed at root' and 'allowed child content types' of content/media/member types to the permissions property;

  • Migrating the data type configuration from pre-values to the correct configuration objects and new editor aliases for:

    • Umbraco.CheckBoxList (pre-values to value list)

    • Umbraco.ColorPickerAlias to Umbraco.ColorPicker (pre-values to value list)

    • Umbraco.ContentPicker2 to Umbraco.ContentPicker (removes invalid start node ID)

    • Umbraco.ContentPickerAlias to Umbraco.ContentPicker (removes invalid start node ID)

    • Umbraco.Date to Umbraco.DateTime

    • Umbraco.DropDown to Umbraco.DropDownListFlexible (pre-values to value list, single item select)

    • Umbraco.DropDownListFlexible (pre-values to value list, defaults to multiple item select)

    • Umbraco.DropdownlistMultiplePublishKeys to Umbraco.DropDownListFlexible (pre-values to value list, defaults to multiple item select)

    • Umbraco.DropdownlistPublishingKeys to Umbraco.DropDownListFlexible (pre-values to value list, defaults to single item select)

    • Umbraco.DropDownMultiple to Umbraco.DropDownListFlexible (pre-values to value list, defaults to multiple item select)

    • Umbraco.MediaPicker2 to Umbraco.MediaPicker (removes invalid start node ID, defaults to single item select)

    • Umbraco.MediaPicker (removes invalid start node ID)

    • Umbraco.MemberPicker2 to Umbraco.MemberPicker

    • Umbraco.MultiNodeTreePicker2 to Umbraco.MultiNodeTreePicker (removes invalid start node ID)

    • Umbraco.MultiNodeTreePicker (removes invalid start node ID)

    • Umbraco.MultipleMediaPicker to Umbraco.MediaPicker (removes invalid start node ID, defaults to multiple item select)

      • Umbraco.NoEdit to Umbraco.Label

    • Umbraco.RadioButtonList (pre-values to value list, change database type from integer to nvarchar)

    • Umbraco.RelatedLinks2 to Umbraco.MultiUrlPicker

    • Umbraco.RelatedLinks to Umbraco.MultiUrlPicker

    • Umbraco.Textbox to Umbraco.TextBox

    • Umbraco.TextboxMultiple to Umbraco.TextArea

    • Umbraco.TinyMCEv3 to Umbraco.TinyMCE

  • Migrating pre-value property values for:

    • Umbraco.CheckBoxList

    • Umbraco.DropDown.Flexible

    • Umbraco.RadioButtonList

The following composer adds the required legacy artifact type resolver and migrators, plus a custom resolver that marks the specified document type alias testElement as element type. Element types are a concept added in Umbraco 8 and is required for document types that are used in Nested Content.

LegacyImportComposer.cs (configure artifact type resolver and artifact migrators)
using Umbraco.Cms.Core.Composing;
using Umbraco.Deploy.Contrib.Migrators.Legacy;

internal class LegacyImportComposer : IComposer
{
    public void Compose(IUmbracoBuilder builder)
    {
        builder.DeployArtifactTypeResolvers()
            .AddLegacyTypeResolver();

        builder.DeployArtifactMigrators()
            .AddLegacyMigrators()
            .Append<ElementTypeArtifactMigrator>();
    }

    private class ElementTypeArtifactMigrator : ElementTypeArtifactMigratorBase
    {
        public ElementTypeArtifactMigrator()
            : base("testElement")
        { }
    }
}

It is recommended to first only import schema and schema files (by deselecting 'Content' and 'Content files' in the dialog), followed by a complete import of all content and schema. The order in which the artifacts are imported depends on the dependencies between them, so this ensures the schema is completely imported before any content is processed.

Obtaining Umbraco Deploy for Umbraco 7

Umbraco Deploy for Umbraco 7 is no longer supported and was only available on Umbraco Cloud. It was not released for use on-premise.

As such if you are looking to migrate from an Umbraco Cloud project running on Umbraco 7, you already have Umbraco Deploy installed.

If you have an Umbraco 7 on-premise website, you can use this guide to migrate from on-premise to Umbraco Cloud or to upgrade to a newer Deploy version on-premise. You will need to obtain and install Umbraco Deploy for Umbraco 7 into your project, solely to use the export feature.

The export feature can be used without a license.

A license is required for the Umbraco project you are importing into - whether that's a license that comes as part of an Umbraco Cloud subscription, or an on-premise one.

Use this guide to migrate from on-premise to Umbraco Cloud or to upgrade to a newer Deploy version on-premise.

  1. Download the required dll files for Umbraco Deploy for Umbraco 7 from the following links:

  • Umbraco Deploy v2.1.6: Latest Deploy Version 2 release for Umbraco CMS Version 7 (officially for use on Cloud)

  • Umbraco Deploy Contrib v2.0.0: Latest/only Deploy Contrib Version 2

  • Umbraco Deploy Export v2.0.0: For exporting all content/schema in Version 7

  1. Install Umbraco Deploy with the Contrib and Export extensions.

  • Install Umbraco Deploy, Deploy.Contrib, and Deploy.Export by copying the downloaded .dll files into your Umbraco 7 site.

  • When copying the files over from Umbraco Deploy you should not overwrite the following files (if you already had Umbraco Deploy installed):

 Config/UmbracoDeploy.config
 Config/UmbracoDeploy.Settings.config
  • Run the project to make sure it runs without any errors

  1. Update the web.config file with the required references for Umbraco Deploy:

web.config
<?xml version="1.0"?> 
<configSections>
    <sectionGroup name="umbraco.deploy">
      <section name="environments" type="Umbraco.Deploy.Configuration.DeployEnvironmentsSection, Umbraco.Deploy" requirePermission="false" />
      <section name="settings" type="Umbraco.Deploy.Configuration.DeploySettingsSection, Umbraco.Deploy" requirePermission="false" />
    </sectionGroup>
  </configSections>
  <umbraco.deploy>
    <environments configSource="config\UmbracoDeploy.config" />
    <settings configSource="config\UmbracoDeploy.Settings.config" />
  </umbraco.deploy>
</configuration>
  1. Export Content.

  • Export your content, schema, and files to zip.

Service details (programmatically importing and exporting)

Underlying the functionality of import/export with Deploy is the import/export service, defined by the IArtifactImportExportService.

You may have need to make use of this service directly if building something custom with the feature. For example you might want to import from or export to some custom storage.

The service interface defines two methods:

  • ExportArtifactsAsync - takes a collection of artifacts and a storage provider defined by the IArtifactExportProvider interface. The artifacts are serialized and exported to storage.

    • IArtifactExportProvider defines methods for creating streams for writing serialized artifacts or files handled by Deploy (media, templates, stylesheets etc.).

  • ImportArtifactsAsync - takes storage provider containing an import defined by the IArtifactImportProvider interface. The artifacts from storage are imported into Umbraco.

    • IArtifactImportProvider defines methods for creating streams for reading serialized artifacts or files handled by Deploy (media, templates, stylesheets etc.).

Implementations for IArtifactExportProvider and IArtifactImportProvider are provided for:

  • A physical directory.

  • An Umbraco file system.

  • A zip file.

These are all accessible for use via extension methods available on IArtifactImportExportService found in the Umbraco.Deploy.Infrastructure.Extensions namespace.

The following example shows this service in use, importing and exporting from a zip file on startup:

ArtifactImportExportComposer.cs (import and export on startup)
using System.IO.Compression;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Composing;
using Umbraco.Cms.Core.Deploy;
using Umbraco.Cms.Core.Events;
using Umbraco.Cms.Core.Extensions;
using Umbraco.Cms.Core.Notifications;
using Umbraco.Deploy.Core;
using Umbraco.Deploy.Core.Connectors.ServiceConnectors;
using Umbraco.Deploy.Infrastructure;
using Umbraco.Deploy.Infrastructure.Extensions;
​
internal class ArtifactImportExportComposer : IComposer
{
    public void Compose(IUmbracoBuilder builder)
        => builder.AddNotificationAsyncHandler<UmbracoApplicationStartedNotification, ArtifactImportExportStartedAsyncHandler>();
​
    private sealed class ArtifactImportExportStartedAsyncHandler : INotificationAsyncHandler<UmbracoApplicationStartedNotification>
    {
        private readonly IHostEnvironment _hostEnvironment;
        private readonly IArtifactImportExportService _diskImportExportService;
        private readonly IServiceConnectorFactory _serviceConnectorFactory;
        private readonly IFileTypeCollection _fileTypeCollection;
​
        public ArtifactImportExportStartedAsyncHandler(IHostEnvironment hostEnvironment, IArtifactImportExportService diskImportExportService, IServiceConnectorFactory serviceConnectorFactory, IFileTypeCollection fileTypeCollection)
        {
            _hostEnvironment = hostEnvironment;
            _diskImportExportService = diskImportExportService;
            _serviceConnectorFactory = serviceConnectorFactory;
            _fileTypeCollection = fileTypeCollection;
        }
​
        public async Task HandleAsync(UmbracoApplicationStartedNotification notification, CancellationToken cancellationToken)
        {
            var deployPath = _hostEnvironment.MapPathContentRoot(Constants.SystemDirectories.Data + "/Deploy");
            await ImportAsync(Path.Combine(deployPath, "import.zip"));
​
            Directory.CreateDirectory(deployPath);
            await ExportAsync(Path.Combine(deployPath, $"export-{DateTimeOffset.UtcNow.ToUnixTimeSeconds()}.zip"));
        }
​
        private async Task ImportAsync(string zipFilePath)
        {
            if (File.Exists(zipFilePath))
            {
                using ZipArchive zipArchive = ZipFile.OpenRead(zipFilePath);
                await _diskImportExportService.ImportArtifactsAsync(zipArchive);
            }
        }
​
        private async Task ExportAsync(string zipFilePath)
        {
            using ZipArchive zipArchive = ZipFile.Open(zipFilePath, ZipArchiveMode.Create);
​
            IEnumerable<Udi> udis = DeployEntityTypes.GetEntityTypes(_fileTypeCollection, DeployEntityTypeCategories.ContentAndSchema).Select(Udi.Create);
            var contextCache = new DictionaryCache();
            string[] dependencyEntityTypes = DeployEntityTypes.GetEntityTypes(_fileTypeCollection, DeployEntityTypeCategories.All);
​
            await _diskImportExportService.ExportArtifactsAsync(_serviceConnectorFactory, udis, Constants.DeploySelector.ThisAndDescendants, contextCache, zipArchive, dependencyEntityTypes: dependencyEntityTypes);
        }
    }
}

Installing Umbraco Deploy

In this article, we will cover the steps in order for you to install and configure Umbraco Deploy on a new or existing website.

Prerequisites

Ensure to first read and follow the setup guides for either new or existing projects below:

New project

Here we will cover how to install and set up Umbraco Deploy on a new website.

Requirement

  • Visual Studio 2017 v15.9.6 or later

  • Umbraco Deploy license

  • SQL Server Database

Set up the Git repository and Umbraco project

The first step to get Umbraco Deploy up and running is to set up a GitHub repository. This will be where source code is stored, and, following the GitHub Actions example, act as our environment where we will set up a CI/CD pipeline.

  1. Using the Visual Studio template, set up a GitHub repository with a .gitignore file.

  2. Clone down the repository to your local machine.

  3. Create a new Umbraco project.

  4. Run the project.

  5. Choose to use a custom SQL connection string pointing to your local database.

  6. Commit the files so they are ready to be pushed up once we have set up the build server.

When Umbraco has been installed in a repository, we can continue to install and configure Umbraco Deploy in the project.

Existing project

Here we will cover the steps in order for you to install Umbraco deploy on your already existing website with content.

We will cover how to install and set up Umbraco deploy on your website and how to generate the UDA files based on your production website's database.

Requirement

  • Visual Studio 2017 v15.9.6 or later

  • Umbraco Deploy license

  • Copy of your production site's database

  • Copy of views, CSS, and scripts folder from production

Step 1: Install Umbraco Deploy on Existing site

To install Umbraco Deploy on an existing site there are additional steps that need to be taken so Umbraco Deploy can run with your website. On an existing Umbraco website, there is already a set of Document Types, Templates, and Data Types with IDs in the database. In order for Umbraco Deploy to work with your website, you will need to make sure that these IDs are in sync between the different environments that you want to add to your setup.

  1. Make a copy of the database on the production site.

  2. Download your /Views folder as well as the folders holding your css files and scripts.

When the production database, folder, and files have been copied down, it's time to set up a git repository and a new Umbraco project.

Step 2: Set up Git repository and Umbraco project

The next step to get Umbraco Deploy up and running is to set up a repository and install Umbraco into it.

  1. Set up a repository with a .gitignore file using the Visual Studio template.

  2. Clone down the repository to your local machine.

  3. Create a new Umbraco project.

  4. Use the copy of your production Database when setting up the database for the empty project.

  5. Add the /Views folder as well as the folders holding your css files and scripts.

  6. Commit the files so they are ready to be pushed up once you have set up the build server.

  7. Run the project.

When Umbraco has been installed in a repository, we can continue to install and configure Umbraco Deploy in the project.

Source Control Configuration

After the Umbraco files have been committed add the following lines to the .gitignore so that they will not be picked up by Git when we are deploying.

**/media/*

# Umbraco deploy specific
**/umbraco/Deploy/deploy*

The deploy-specific update here will ensure that temporary files generated by Deploy during its operations will not be included in source control.

Make sure that the updates to the .gitignore file are also committed.

Installing and Configuring Umbraco Deploy

When Umbraco has been installed in a repository, we can install Umbraco Deploy in the project.

To install Umbraco Deploy, run dotnet add package Umbraco.Deploy.OnPrem from the command line or Install-Package Umbraco.Deploy.OnPrem from the package manager console in Visual Studio.

To be able to use Umbraco Forms with Umbraco Deploy, you need to install the Umbraco.Deploy.Forms package as well.

In order to deploy content based on certain rich core and community property editors - including Multi URL Picker and Block List Editor - there is one further NuGet package to install: Umbraco.Deploy.Contrib.

When Umbraco Deploy has been installed, to be able to use it in the project you will need to create and add configuration for an API key.

The API key should be a randomly generated string of 64 characters (recommended). The minimum requirement is 10 characters.

You can use the following C# code to generate the API key:

using System;
using System.Security.Cryptography;

byte[] secret = new byte[32];
RandomNumberGenerator.Create().GetBytes(secret);

var apiKey = new StringBuilder(secret.Length * 2);
for (int i = 0; i < secret.Length; i++)
{
   apiKey.AppendFormat("{0:X2}", secret[i]);
}

Console.Write(apiKey.ToString());

Or by running the following PowerShell command:

$secret = [byte[]]::new(32); [System.Security.Cryptography.RandomNumberGenerator]::Create().GetBytes($secret); return -join ($secret | %{ '{0:X2}' -f $_ })

This same Deploy API key must be used on each environment for the same website.

We strongly recommend generating different keys for different websites/projects.

The key should be applied in appsettings.json.

{
  "Umbraco": {
    "Deploy": {
        "Settings": {
            "ApiKey": "<your API key here>",
        }
    }
  }
}

Configuring Environments

Once the API key has been added, it is now time to configure the environments, also in the appsettings.json file.

An example configuration with a single upstream environment file will look like this:

{
   "Umbraco": {
      "Deploy": {
         "Settings": {
            "ApiKey": "<your API key here>"
         },
         "Project": {
            "CurrentWorkspaceName": "Live",
            "Workspaces": [
               {
                  "Id": "efef5e89-a19b-434b-b68a-26e022a0ad52",
                  "Name": "Live",
                  "Type": "live",
                  "Url" :"https://localhost:44307"
               }
            ]
         }
      }
   }
}

The setting under Project:CurrentWorkspaceName should match the Name provided in the list of Workspaces that match the current environment. Using this Umbraco Deploy will indicate the correct current environment on the "Workspaces" dashboard.

In Umbraco Deploy 9, this value was set using the configuration key Debug:EnvironmentName. Although included under a "Debug" section, this setting is required for the installations of Umbraco Deploy on-premises (i.e. other than on Umbraco Cloud). Hence why it was moved to the "Project" section in Umbraco Deploy 10.

Expected values for Type are "development", "staging" or "live". These settings are required, though strictly only for the latter is it necessary to use the specific value of "live", so other values can be used if you have more than these three environments.

You will need to generate a unique GUID for each environment. This can be done in Visual Studio:

  1. Open "Tools".

  2. Select "Create GUID".

  3. Use the Registry Format.

  4. Copy the GUID into the id value.

  5. Generate a "New GUID" for each environment you will be adding to your setup.

Or by running the following PowerShell command:

[guid]::NewGuid().ToString()

The URL configured for each environment should be the root URL for the website and needs to be accessible by the other environments over HTTPS.

Validating Source Control

Once the configuration has been set up with the correct information we can now go ahead and make sure that the source control is including our files in the /umbraco/Deploy folder of our Umbraco project.

This can be done by going to the /umbraco/Deploy/Revision folder of the project and create a test .uda file, and then check in either your Git GUI or in the command line and verify whether the test file is being tracked.

Test UDA file

We can see that the file has been created and it is being tracked by Git and we can go ahead and delete the test file.

Now that Umbraco Deploy has been installed on the project, we can go ahead and commit the files to the repository.

Do not push the files up yet as a CI/CD build server will first need to be set up and connected to our repository.

Include your Umbraco Deploy license file

Before moving on to setting up the build server, make sure that your license is included in your project.

The file needs to be placed in the /umbraco/Licenses folder.

Read more about the Umbraco Deploy licensing model.

Release notes

Get an overview of the things changed and fixed in each version of Umbraco Deploy.

In this section we have summarised the changes to Umbraco Deploy and Deploy Contrib released in each version. Each version is presented with a link to the Deploy issue tracker showing a list of issues resolved in the release. We also link to the individual issues themselves from the detail.

If there are any breaking changes or other issues to be aware of when upgrading they are also noted here.

If you are upgrading to a new major version you can find the details about the breaking changes in the version specific updates article.

Release History

This section contains the release notes for Umbraco Deploy 4 and 10 including all changes for these versions. For each major version, you can find the details about each release.

10.4.1 (November 29th 2024)

  • Add [DisableRequestSizeLimit] attribute to UploadForImport endpoint to remove application request size limit (server/infrastructure restrictions may still apply)

  • Fixed issue where content was not saved when transferring variant content with a release date

  • Support flexible environments on Umbraco Cloud (remove requirement for environment types to be Development, Staging or Live)

  • Update documentation links in management dashboard to include major version in the URL

10.4.0 (March 19th 2024)

  • All items from 10.4.0-rc1

  • Fixed issue with transfer of date values within Nested Content, Block List or Block Grid properties #209

  • Back-ported fix where templates could incorrectly cause schema mismatch errors when running in production mode. Although runtime modes aren't available in Umbraco 8, we ensure that the template .uda files are correctly processed by always setting the template path. #187

  • Fixed issue where importing invalid variant property data would cause a not supported variation exception #8

  • Fixed deserialization issue causing problems with the compare content feature #212

10.4.0-rc1 (March 5th 2024)

  • Add IArtifactTypeResolver to allow custom type resolving when deserializing to IArtifact (used by Deploy Contrib, see PR #60)

  • Add base migrators for importing legacy artifacts (used by Deploy Contrib)

  • Restored ability to overwrite content properties with empty values

  • Improved error UX and messaging to only show technical detail option if available

  • Require a valid license when importing

10.3.4 (February 20th 2024)

  • Removed the no-longer supported "live edit" feature (Deploy on Cloud only).

  • Fixed issue where the removal of a master template couldn't be deployed #201

  • Ensured configuration for behavior following a "path too long" exception is respected for handling image cropper values #200

  • User experience and message improvements on content flow exception #202

  • Fixed issue with transfer of empty values to overwrite non-empty ones.

10.3.3 (January 16th 2024)

  • Added configurable option to avoid overwriting of dictionary items with empty values #191

    • For more details see the page on Deploy's settings.

  • Fixed regression issue with transfer of date values.

10.3.2 (January 9th 2024)

  • Fixed issue with transfer of content using language variants #193

10.3.1 (December 21th 2023)

  • Fixes the display of the selected schedule date on queue for transfer.

  • Fixes parsing property values within Nested Content and Block List that were previously saved by the Contrib value connectors.

  • Fixed incorrectly including media files in export when 'Content files' wasn't selected.

  • Add maximum file size validation to import file upload.

10.3.0 (December 11th 2023)

  • All items from 10.3.0-rc1.

  • Fixed a regression in 10.3.0-rc1 where content restore/transfers didn't use the same JSON converters when deserializing Deploy artifacts.

  • Fixed permissions not being correctly set for administrators on initial install.

  • Moved permissions from the Content to a new Deploy category (only affecting the UI).

  • Add support for migrating property values within Nested Content, Block List and Block Grid, and include Multi URL Picker value connector (an explicit value connector binding is used to override the ones provided in Deploy Contrib).

  • Added new configuration option of TrashedContentDeploymentOperations to allow exporting/importing of trashed content, ensuring referenced content in the recycle bin isn't exported by default and otherwise imports back into the recycle bin.

  • Changed the default value connector to use the property storage type, instead of using custom value prefixes to store the object type.

10.3.0-rc1 (November 27th 2023)

  • Added feature of content import and export with migrations.

  • Added a new configuration option of ResolveUserInTargetEnvironment to allow resolving of user accounts in target environments (see Deploy Settings).

  • Added a new configuration option of AllowPublicAccessDeploymentOperations to amend the behavior of public access rule transfer (see Deploy Settings).

  • Improve performance of publishing multi-language content during restore/transfer and import.

10.2.7 (November 14th 2023)

  • Fixed action menu for queue for transfer with list view #185.

10.2.6 (October 17th 2023)

  • Fixed issue with deployment of content when scheduled for a future release date.

  • Prevent dictionary items from being serialized to .uda files on disk when configured for transfer as content #184.

10.2.5 (October 10th 2023)

  • Fixed regression issue introduced in 10.2.4 with deployment of properties of content templates #182

10.2.4 (September 19th 2023)

  • Updated the transfer of user picker values to resolve the user by username in the target environment #180

  • Also updated the logic for the member picker to ensure values representing members that don't exist in the target environment are cleared.

  • Added configuration option to ignore missing languages when deploying translation items #176

  • Ensured consistent sort of translations within dictionary items .uda files #175

  • Ensured that alt text for images placed in grid cells are transferred #174

  • Further fix to logic for creating redirects on content deployment for variant content #170

  • Resolves issue with grid media items in a batched deployment operation.

  • Increased size of database fields storing references to account for longer values used in package data Commerce #428

  • Include published name in content transfer data to avoid overwriting with draft name if different.

  • Optimized content transfers to include only draft and published versions when they exist.

  • Fixed issue with partial restore of forms #178

10.2.3 (August 1st 2023)

  • Ensured that schema files are updated on entity container renames #171.

  • Fixed issue with processing of marker files on Linux #169.

  • Corrected logic for creating redirects on content deployment for variant content.

  • Ensured consistent rendering of trailing zeros when using the rounded decimal converter.

  • Reduced some logging to debug to reduce noise in log files.

10.2.2 (May 30th 2023)

  • Resolved a low impact security issue found in internal testing when triggering a schema extraction.

10.2.1 (May 23rd 2023)

  • Added configuration for batch package processing and omitting post operation notification handlers.

  • Handled use of trailing slash in configured environment URLs.

  • Added sort option for the "is up to date" column in the schema comparison #165.

  • Ensured artifacts serialized to disk are no longer processed when the entity is configured to be transferred as content.

  • Handled updates to serialized document types on deletion of data types.

10.2.0 (April 11th 2023)

  • Restricted languages available to editors when deploying variant content to those allowed via the user permissions for languages.

  • Tidied up the Deploy dialogs for transfer, compare and restore to align with CMS conventions and remove redundant options.

  • Added a database lock to the persistent transfer queue, removing any risk of concurrency issues when adding or removing items from the queue.

  • Added support for new form properties introduced in the most recent minor release of Forms 11. #161

10.1.4 (March 21st 2023)

  • Fixed issue with transfer of form workflow's "sensitive data" property. #159

  • Fixed issue with datatype not found on cache rebuild #157

  • Resolved issue with progress bar initialization on partial restore dialog

  • Handled file not found issue when calculating media file checksum using file metadata

  • Avoided exception triggered by custom tree implementations that do not expose an alias #160

10.1.2 (November 15th 2022)

  • Added batch settings option providing resolution to large content or media transfers hitting Azure service limit #128

10.1.1 (October 18th 2022)

  • Resolved issue with media restore when database items exist and files don't (backport fix to V4) #123

  • Fixed issue with use of HTTP timeout setting (V9+)

10.1.0 (September 7th 2022)

  • Introduced and used caching in deploy operations to improve performance.

  • Increased default and added setting for disk operation timeouts #135

  • Single language content transfers #132

  • Scheduled content transfers.

  • Corrected transfer of unpublished content status #131

  • Improved UX and descriptions in backoffice settings dashboard #118

  • Added ability to download Deploy artifacts (.uda files) as a zip archive from the management dashboard.

  • Added sort options to the schema comparison view in the management dashboard #115

  • Indented the JSON representation of Data Type configuration details in the .uda files for ease of review #85

  • Fixed issue with transfer of Forms prevalue sources from text files that include captions.

  • Ensured Document Type validation messages are transferred between environments #137

  • Fixed issue with scheduled publish date being time shifted on deployments when source and target servers are running in different timezones.

  • Fixed issue with transfer for members of a given type (V10 only) #139

10.0.3 (August 16th 2022)

  • Aligned Git URL displayed in backoffice with that in Cloud Portal (V4 only) #136

  • Fixed issue with deployment of root node value for Umbraco Forms's "save as Umbraco node" workflow #133

  • Fixed incorrect availability of workspace restore in production environment (V9 and V10 only)

  • Added close button to "Transfer now" dialog

  • Resolved registration of deployable types to support configuration for "backoffice edition".

10.0.2 (July 12th 2022)

  • Resolved issue with media restore when database items exist and files don't #123

  • Added details of failed deployment to deploy dashboard #120

  • Added copy button for deploy log in the backoffice #121

  • Fixed typo in UI #113

  • Ensured signature refresh on Data Type move into or out of folder #125

  • Fixed selection of workspace for compare dialog

  • Optimized existence checks in connectors

  • Restore missing partial restore option in content and media tree roots (V9+)

  • Fixed extract trigger URL in PowerShell script distributed with Deploy On-Premise (V9+)

  • Improved deserialization of exceptions for clearer reporting (V9+)

10.0.1 (June 29th 2022)

  • Fixed issue with deployment of content using variant properties #126

10.0.0 (June 16th 2022)

  • Compatibility with .NET 6 and Umbraco 10

Version 4

4.10.0 (March 19th 2024)

  • All items from 4.10.0-rc1

  • Fixed issue with transfer of date values within Nested Content, Block List or Block Grid properties #209

  • Fixed issue where templates could incorrectly cause schema mismatch errors when running in production mode #187

  • Fixed issue where importing invalid variant property data would cause a not supported variation exception #8

  • Fixed deserialization issue causing problems with the compare content feature #212

4.10.0-rc1 (March 5th 2024)

  • Add IArtifactTypeResolver to allow custom type resolving when deserializing to IArtifact (used by Deploy Contrib, see PR #60)

  • Add base migrators for importing legacy artifacts (used by Deploy Contrib)

  • Restored ability to overwrite content properties with empty values

  • Improved error UX and messaging to only show technical detail option if available

  • Require a valid license when importing

  • Remove Microsoft.Owin.Cors and Microsoft.AspNet.Cors dependencies

4.9.4 (February 20th 2024)

  • Removed the no-longer supported "live edit" feature (Deploy on Cloud only).

  • Fixed issue where the removal of a master template couldn't be deployed #201

  • Ensured configuration for behavior following a "path too long" exception is respected for handling image cropper values #200

  • User experience and message improvements on content flow exception #202

  • Fixed issue with transfer of empty values to overwrite non-empty ones.

4.9.3 (January 16th 2024)

  • Added configurable option to avoid overwriting of dictionary items with empty values #191

    • For more details see the page on Deploy's settings.

  • Fixed regression issue with transfer of date values.

4.9.2 (January 9th 2024)

  • Fixed issue with transfer of content using language variants #193

4.9.1 (December 21th 2023)

  • Fixes the display of the selected schedule date on queue for transfer.

  • Fixes parsing property values within Nested Content and Block List that were previously saved by the Contrib value connectors.

  • Fixed incorrectly including media files in export when 'Content files' wasn't selected.

  • Add maximum file size validation to import file upload.

4.9.0 (December 11th 2023)

  • All items from 4.9.0-rc1.

4.9.0-rc1 (November 27th 2023)

  • Added feature of content import and export with migrations.

  • Added a new configuration option of ResolveUserInTargetEnvironment to allow resolving of user accounts in target environments (see Deploy Settings).

  • Added a new configuration option of AllowPublicAccessDeploymentOperations to amend the behavior of public access rule transfer (see Deploy Settings).

4.8.4 (October 10th 2023)

  • Fixed regression issue introduced in 4.8.3 with deployment of properties of content templates #182

4.8.3 (September 19th 2023)

  • Updated the transfer of user picker values to resolve the user by username in the target environment #180

  • Also updated the logic for the member picker to ensure values representing members that don't exist in the target environment are cleared.

  • Added configuration option to ignore missing languages when deploying translation items #176

  • Ensured consistent sort of translations within dictionary items .uda files #175

  • Ensured that alt text for images placed in grid cells are transferred #174

  • Further fix to logic for creating redirects on content deployment for variant content #170

  • Resolves issue with grid media items in a batched deployment operation.

  • Increased size of database fields storing references to account for longer values used in package data Commerce #428

  • Include published name in content transfer data to avoid overwriting with draft name if different.

  • Optimized content transfers to include only draft and published versions when they exist.

4.8.2 (August 1st 2023)

  • Corrected logic for creating redirects on content deployment for variant content.

  • Ensured consistent rendering of trailing zeros when using the rounded decimal converter.

  • Reduced some logging to debug to reduce noise in log files.

4.8.1 (May 23rd 2023)

  • Added configuration for batch package processing and omitting post operation notification handlers.

  • Handled use of trailing slash in configured environment URLs.

  • Added sort option for the "is up to date" column in the schema comparison #165.

  • Ensured artifacts serialized to disk are no longer processed when the entity is configured to be transferred as content.

  • Handled updates to serialized document types on deletion of data types.

4.8.0 (April 11th 2023)

  • Tidied up the Deploy dialogs for transfer, compare and restore to align with CMS conventions and remove redundant options.

  • Added a database lock to the persistent transfer queue, removing any risk of concurrency issues when adding or removing items from the queue.

4.7.4 (March 21st 2023)

  • Fixed issue with datatype not found on cache rebuild #157

4.7.3 (February 21st 2023)

  • All items listed under the 9.5.3, 10.1.3 and 11.0.1 releases (other than those indicated as only applying to higher versions).

4.7.2 (November 15th 2022)

  • Added batch settings option providing resolution to large content or media transfers hitting Azure service limit #128

4.7.1 (October 18th 2022)

  • Resolved issue with media restore when database items exist and files don't (backport fix to V4) #123

  • Fixed issue with use of HTTP timeout setting (V9+)

4.7.0 (September 22nd 2022)

  • Fixed issue with scheduled publish date being time shifted on deployments when source and target servers are running in different timezones.

  • Fixed issue with transfer for members of a given type (V10 only) #139

  • Introduced and used caching in deploy operations to improve performance.

  • Increased default and added setting for disk operation timeouts #135

  • Single language content transfers #132

  • Scheduled content transfers.

  • Corrected transfer of unpublished content status #131

  • Improved UX and descriptions in backoffice settings dashboard #118

  • Added ability to download Deploy artifacts (.uda files) as a zip archive from the management dashboard.

  • Added sort options to the schema comparison view in the management dashboard #115

  • Indented the JSON representation of Data Type configuration details in the .uda files for ease of review #85

  • Fixed issue with transfer of Forms prevalue sources from text files that include captions.

  • Ensured Document Type validation messages are transferred between environments #137

4.6.2 (August 16th 2022)

  • Aligned Git URL displayed in backoffice with that in Cloud Portal (V4 only) #136

  • Fixed issue with deployment of root node value for Umbraco Forms's "save as Umbraco node" workflow #133

  • Fixed incorrect availability of workspace restore in production environment (V9 and V10 only)

  • Added close button to "Transfer now" dialog

  • Resolved registration of deployable types to support configuration for "backoffice edition".

4.6.1 (July 12th 2022)

  • Resolved issue with media restore when database items exist and files don't #123

  • Added details of failed deployment to deploy dashboard #120

  • Added copy button for deploy log in the backoffice #121

  • Fixed typo in UI #113

  • Ensured signature refresh on Data Type move into or out of folder #125

  • Fixed selection of workspace for compare dialog

  • Optimized existence checks in connectors

  • Restore missing partial restore option in content and media tree roots (V9+)

  • Fixed extract trigger URL in PowerShell script distributed with Deploy On-Premise (V9+)

  • Improved deserialization of exceptions for clearer reporting (V9+)

4.6.0 (April 26th 2022)

  • Retained compact JSON formatting when transferring grid values

  • Enhancements to content comparison dialog #101

  • Partial restore for Forms and third-party plugins #100

  • Display of configuration information and schema comparison on the deploy "settings" dashboard.

  • Deployment of culture & hostname details #107

  • Optional, automated clear of memory cache

  • Resolved issue with empty value deployment of content based on the tags property editor #104

  • Resolved issue with redirect functionality when records are deployed between environments (part of CMS #10066)

  • Surfaced information about configuration for the ignore of broken dependencies in the dialog that presents the error information

  • Fixed a CSS rendering issue for the deploy content dashboard's workspace display, when more than four environments are available.

  • Fixed issue with deployment of empty tags data #104

4.5.0 (February 15th 2022)

  • Content comparison dialog #65

  • Backoffice deployment of members and member groups.

  • Added support for deployment of history clean-up settings on Document Types (V4 only)

  • Fixed bug with deployments of templates involving alias renames

4.4.4 (February 15th 2022)

  • Fixed content transfer issue when public access login and error pages are created below the protected page #99

  • Fixed issue with clashing permission letter for "queue for transfer" menu option (V4 only) #95

4.4.3 (January 25th 2022)

  • Fixed ambiguous match exception when deploying forms (V4 only) #97

  • Fixed issue with "live edit" component and scheduled publishing (V9 only) #98

  • Amends to timing of file operation initialization to ensure third party components complete setup (V9 only).

  • Added .NET 6 version of environment variable syntax for Umbraco Cloud configuration settings.

4.4.2 (December 21st 2021)

  • Fixed issue with extractions triggered from uda files generated from older versions without property group aliases. #92

  • Fixed timing issue for initiation of reading of file system triggers impacting third party Deploy integrations. #91

4.4.1 (December 7th 2021)

  • Fixed issue relating to deployment of image alt text within the rich text editor. #87

4.4.0 (November 2nd 2021)

  • Separate operations for "tree" and "workspace" restore #66

  • Finer configuration options for ignoring broken dependencies #81

  • Removed the redundant and misleading deploy operations available on the form "entries" menu item. #83

  • Fixed issue with operations involving Form prevalue sources using XPath. #69​

  • Fixed issue with restore options when Forms 8.8 is used with form definitions stored on disk. #76

  • Improved reliability of extractions triggered from Umbraco Cloud git deployment operations by introducing a new marker file used only on start-up.

  • Improved reliability of extractions on new Cloud infrastructure by wrapping and throttling the file system watcher events.

  • Fixed issues with styling and scripts on the custom “no content” page displayed when Deploy is used.

  • Fixed issue with language deployment when fallbacks are configured.

  • Improved the error reporting when authorization fails between environments (V9 only). #77

  • Fixed issue with restore of empty tab alias #84

4.3.0 (October 7th 2021)

  • Added support for deployment of CMS tabs and groups

  • Fixed issue with JSON detection causing issues using square brackets in grid content #70

4.2.0 (August 19th 2021)

  • Added support for deployment of form folders #75 (Forms)

  • Added support for backoffice transfer of data from custom packages or solutions

  • Provided option for deploying dictionary items "as content" #17 #56

  • List multiple dependency errors when deploying or restoring #5

  • Add additional detail about deployment errors into logs #40

  • Alter structure of .uda files to put name and alias at the top #50

  • Fixed issue with removal of used macro parameter when restoring #53

  • Add deep-link to deploy dashboard from transfer queue, so will be shown on click from "open transfer queue" (if CMS version supports deep dashboard links) #57

  • Added value connector for new media picker #58

  • Added refresh button to queue #61

  • Fixed issue with changing casing of template aliases #63

  • Added clear signature operation for minor updates of Deploy or CMS

  • Fixed issue with forms deployment where workflows are deleted via code.

  • Fixed issue with deploying Form prevalues with Forms versions < 8.5 #23

4.1.4 (September 7th 2021)

  • Resolution of issue with failed extractions on vNext infrastructure.

4.1.3 (August 3rd 2021)

  • Resolution of issue with failed extractions on vNext infrastructure.

4.1.1 (April 27th 2021)

  • Added serialization converter for control of number of decimal places - #465 (internal)

  • Resolved issue with deployment of content schedule - #445 (internal) and #31

  • Resolved issue with unnecessary empty records being created in destination database - #444 (internal)

  • Resolved issue with transfer of content templates when variants are enabled - #385 (internal)

  • Resolved issues with content restore progress not updating when custom dashboards are installed - #39 and #47

  • Resolved issue with deployment of changes to default language - #32

  • Resolved issue with deployment of empty values not replacing previously entered content - #1

  • Removed "transfer now" button from users that don't have permission to "queue for transfer" - #25

  • Added deployment of member only property type properties (e.g. "view on profile") - #21

  • Cleared pre-values cache on form deployments - #43

  • Ensured datatype move action triggered serialization and allows deployment to target environment - #10

  • Resolve UI issue where dialog closes if not accurate on selecting node from target environment for restore - #4

4.1.0 (March 25th 2021)

  • Management dashboard for triggering and viewing status of deployment operations

  • Release of Deploy On-Premises

4.0.1 (March 23rd 2021)

  • Enabling Deploy 4 to work in new Cloud infrastructure

Deploy Contrib

10.3.0 (August 15th 2024)

  • All items from 10.3.0-rc1

10.3.0-rc1 (July 19th 2024)

  • Skip empty pre-values #63

  • Add DocTypeGridEditor Data Type configuration connector #65

10.2.0 (March 19th 2024)

  • All items from 10.2.0-rc1

10.2.0-rc1 (March 5th 2024)

  • Add legacy migrators and type resolver to allow importing from Umbraco 7 in #61

10.1.1 (February 14th 2023)

  • Block grid editor support and fix for null reference exception (10+)

  • Further caching for deploy operations.

10.1.0 (September 7th 2022)

  • Fixed issue with transfer of nested content string values using item templates (which is commencing with "{{") that were erroneously considered as JSON in #56

10.1.0-rc001 (September 7th 2022)

  • Updated connectors to use context cache in #54

10.0.1 (July 12th 2022)

  • Optimized existence checks in connectors

10.0.0 (June 15th 2022)

  • Updated Deploy and CMS dependencies to v10

Version 4

4.4.0 (August 15th 2024)

  • All items from 4.4.0-rc1

4.4.0-rc1 (July 19th 2024)

  • Skip empty pre-values #63

  • Add DocTypeGridEditor Data Type configuration connector #65

4.3.0 (March 16th 2024)

  • All items from 4.3.0-rc1

4.3.0-rc1 (March 5th 2024)

  • Add legacy migrators and type resolver to allow importing from Umbraco 7 in #61

4.2.1 (February 21st 2023)

  • Add additional caching using IContextCache in #59

4.2.0 (September 22nd 2022)

  • Fixed issue with transfer of nested content string values using item templates (which is commencing with "{{") that were erroneously considered as JSON in #56

4.2.0-rc001 (September 7th 2022)

  • Used caching in value connectors to improve performance.

4.1.3 (July 12th 2022)

  • Optimized existence checks in connectors

4.1.2 (April 26th 2022)

  • Fixes issue with deployment of nested content properties within Document Type grid editor values in https://github.com/umbraco/Umbraco.Deploy.Contrib/pull/49 (fixes issue #82)

4.1.1 (February 14th 2022)

  • Fixes NullReferenceException when parsing Block Editor values without settings

  • Reduced Nested Content value connector logging level to debug

4.1.0 (September 17th 2021)

  • Added in codes for the DTGE (Doc Type Grid Editor) cell value connector in #39

4.0.0 (May 28th 2021)

  • Make ToArtifact/FromArtifact virtual in #47

Legacy release notes

You can find the release notes for versions out of support in the Legacy documentation on GitHub and Umbraco Deploy Package page.

Extend Deploy

How to extend Umbraco Deploy to synchronize custom data

Umbraco Deploy supports the deployment of CMS schema information and definitions from the HQ's Forms package, along with managed content and media. Additionally, it can be extended by package or custom solution developers. This allows the deployment of custom data, such as that stored in your own database tables.

As a package or solution developer, you can hook into the disk-based serialization and deployment. It is similar to that used for Umbraco Document Types and Data Types. It's also possible to provide the ability for editors to deploy custom data via the Backoffice. In the same way that Umbraco content and media can be queued for transfer and restored.

Concepts and Examples

Entities

Entities are what you may be looking to transfer between two websites using Deploy. Within Umbraco, they are the Document Types, Data Type, documents etc. In a custom solution or a package, there may be representations of some other data that's being stored separately from Umbraco content. These can still be managed in the Backoffice using custom trees and editors.

For the purposes of subsequent code samples, we'll consider an example entity as a Plain Old Class Object (POCO) with a few properties.

The entity has no dependency on Umbraco or Umbraco Deploy; it can be constructed and managed however makes sense for the package or solution. The only requirement is that it has an ID that will be consistent across the environments (normally a Guid) and a name.

public class Example
{
    public Guid Id { get; set; }

    public string Name { get; set; }

    public string Description { get; set; }
}

Artifacts

Every entity Deploy works with, whether from Umbraco core or custom data, needs to have an artifact representation. You can consider an artifact as a container capable of knowing everything there is to know about a particular entity is defined. They are used as a transport object for communicating between Deploy environments.

They can also be serialized to JSON representations. These are visible in the .uda files seen on disk in the /data/revisions/ folder for schema transfers. It is also used when transferring content between different environments over HTTP requests.

Artifact classes must inherit from DeployArtifactBase.

The following example shows an artifact representing the entity and it's single property for transfer:

public class ExampleArtifact : DeployArtifactBase<GuidUdi>
{
    public ExampleArtifact(GuidUdi udi, IEnumerable<ArtifactDependency> dependencies = null)
        : base(udi, dependencies)
    { }

    public string Description { get; set; }
}

Control Over Serialization

In most cases the default settings Umbraco Deploy uses for serialization will be appropriate. For example, it ensures that culture specific values such as dates and decimal numbers are rendered using an invariant culture. This ensures that any differences in regional settings between source and destination servers are not a concern.

If you do need more control, attributes can be applied to the artifact properties.

For example, to ensure a decimal value is serialized to a consistent number of decimal places you can use the following. RoundingDecimalJsonConverter is found in the Umbraco.Deploy.Serialization namespace

[JsonConverter(typeof(RoundingDecimalJsonConverter), 2)]
public decimal Amount { get; set; }

Service Connectors

Service connectors are responsible for knowing how to handle the mapping between artifacts and entities. They know how to gather all the data required for the type of entity they correspond to, including figuring out what dependencies are needed. For example, in Umbraco, how a Document Type depends on a Data Type. They are responsible for packaging an entity as an artifact and for extracting an entity from an artifact and persisting it in a destination site.

Service connectors inherit from ServiceConnectorBase and are constructed with the artifact and entity as generic type arguments.

The class is decorated with a UdiDefinition via which the name of the entity type is provided. This needs to be unique across all entities so it's likely worth prefixing with something specific to your package or application.

The following example shows a service connector, responsible for handling the artifact shown above and it's related entity. There are no dependencies to consider here. More complex examples involve collating the dependencies and potentially handling extraction in more than one pass to ensure updates are made in the correct order.

An illustrative data service is provided via dependency injection. This will be whatever is appropriate for to use for Create, Read, Update and Delete (CRUD) operations around reading and writing of entities.

In Deploy 9.5/10.1, to improve performance on deploy operations, we introduced a cache. This change required the addition of new methods to interfaces, allowing the passing in of a cache parameter. In order to introduce this without breaking changes, we created some new interfaces and base classes.

In the example below, if instead we inherited from ServiceConnectorBase2, which has a type parameter of IServiceConnector2, we would be able to implement IArtifact? IServiceConnector2.GetArtifact(Udi udi, IContextCache contextCache). This would allow the connector to read and write to the cache and remove the use of the obsolete methods.

There's no harm in what is listed below though. It's only that the connectors won't be able to use the cache for any look-ups that are repeated in deploy operations. The obsolete methods won't be removed until Deploy 11. In that version we plan to return back to the original interface and class names. We also plan to introduce the new method overloads which will be a documented breaking change.

[UdiDefinition("mypackage-example", UdiType.GuidUdi)]
public class ExampleServiceConnector : ServiceConnectorBase<ExampleArtifact, GuidUdi, ArtifactDeployState<ExampleArtifact, Example>>
{
    private readonly IExampleDataService _exampleDataService;

    public ExampleServiceConnector(IExampleDataService exampleDataService) => _exampleDataService = exampleDataService;

    public override ExampleArtifact GetArtifact(object o)
    {
        var entity = o as Example;
        if (entity == null)
        {
            throw new InvalidEntityTypeException($"Unexpected entity type \"{o.GetType().FullName}\".");
        }

        return GetArtifact(entity.GetUdi(), entity);
    }

    public override ExampleArtifact GetArtifact(GuidUdi udi)
    {
        EnsureType(udi);
        var entity = _exampleDataService.GetExampleById(udi.Guid);

        return GetArtifact(udi, entity);
    }

    private ExampleArtifact GetArtifact(GuidUdi udi, Example entity)
    {
        if (entity == null)
        {
            return null;
        }

        var dependencies = new ArtifactDependencyCollection();
        var artifact = Map(udi, entity, dependencies);
        artifact.Dependencies = dependencies;

        return artifact;
    }

    private ExampleArtifact Map(GuidUdi udi, Example entity, ICollection<ArtifactDependency> dependencies)
    {
        var artifact = new ExampleArtifact(udi);
        artifact.Description = example.Description;
        return artifact;
    }

    private string[] ValidOpenSelectors => new[]
    {
        DeploySelector.This,
        DeploySelector.ThisAndDescendants,
        DeploySelector.DescendantsOfThis
    };
    private const string OpenUdiName = "All Examples";

    public override void Explode(UdiRange range, List<Udi> udis)
    {
        EnsureType(range.Udi);

        if (range.Udi.IsRoot)
        {
            EnsureSelector(range, ValidOpenSelectors);
            udis.AddRange(_exampleDataService.GetExamples().Select(e => e.GetUdi()));
        }
        else
        {
            var entity = _exampleDataService.GetExampleById(((GuidUdi)range.Udi).Guid);
            if (entity == null)
            {
                return;
            }

            EnsureSelector(range.Selector, DeploySelector.This);
            udis.Add(entity.GetUdi());
        }
    }

    public override NamedUdiRange GetRange(string entityType, string sid, string selector)
    {
        if (sid == "-1")
        {
            EnsureSelector(selector, ValidOpenSelectors);
            return new NamedUdiRange(Udi.Create("mypackage-example"), OpenUdiName, selector);
        }

        if (!Guid.TryParse(sid, out Guid id))
        {
            throw new ArgumentException("Invalid identifier.", nameof(sid));
        }

        var entity = _exampleDataService.GetExampleById(id);
        if (entity == null)
        {
            throw new ArgumentException("Could not find an entity with the specified identifier.", nameof(sid));
        }

        return GetRange(entity, selector);
    }

    public override NamedUdiRange GetRange(GuidUdi udi, string selector)
    {
        EnsureType(udi);

        if (udi.IsRoot)
        {
            EnsureSelector(selector, ValidOpenSelectors);
            return new NamedUdiRange(udi, OpenUdiName, selector);
        }

        var entity = _exampleDataService.GetExampleById(udi.Guid);
        if (entity == null)
        {
            throw new ArgumentException("Could not find an entity with the specified identifier.", nameof(udi));
        }

        return GetRange(entity, selector);
    }

    private static NamedUdiRange GetRange(Example e, string selector) => new NamedUdiRange(e.GetUdi(), e.Name, selector);

    public override ArtifactDeployState<ExampleArtifact, Example> ProcessInit(ExampleArtifact art, IDeployContext context)
    {
        EnsureType(art.Udi);

        var entity = _exampleDataService.GetExampleById(art.Udi.Guid);

        return ArtifactDeployState.Create(art, entity, this, 1);
    }

    public override void Process(ArtifactDeployState<ExampleArtifact, Example> state, IDeployContext context, int pass)
    {
        switch (pass)
        {
            case 1:
                Pass1(state, context);
                state.NextPass = 2;
                break;
            default:
                state.NextPass = -1; // exit
                break;
        }
    }

    private void Pass1(ArtifactDeployState<ExampleArtifact, Example> state, IDeployContext context)
    {
        var artifact = state.Artifact;

        artifact.Udi.EnsureType("mypackage-example");

        var isNew = state.Entity == null;

        var entity = state.Entity ?? new Example { Id = artifact.Udi.Guid };

        entity.Name = artifact.Name;
        entity.Description = artifact.Description;

        if (isNew)
        {
            _exampleDataService.AddExample(entity);
        }
        else
        {
            _exampleDataService.UpdateExample(entity);
        }
    }
}

It's also necessary to provide an extension method to generate the appropriate identifier:

public static GuidUdi GetUdi(this Example entity)
{
    if (entity == null) throw new ArgumentNullException("entity");
    return new GuidUdi("mypackage-example", entity.Id).EnsureClosed();
}

Handling Dependencies

Umbraco entities often have dependencies on one another, this may also be the case for any custom data you are looking to deploy. If so, you can add the necessary logic to your service connector to ensure dependencies are added. This will ensure Umbraco Deploy also ensures the appropriate dependencies are in place before initiating a transfer.

If the dependent entity is also deployable, it will be included in the transfer. Or if not, the deployment will be blocked and the reason presented to the user.

In the following illustrative example, if deploying a representation of a "Person", we ensure their "Department" dependency is added. This will indicate that it must exist to allow the transfer. We can also use ArtifactDependencyMode.Match to ensure the dependent entity not only exists but also matches in all properties.

private PersonArtifact Map(GuidUdi udi, Person person, ICollection<ArtifactDependency> dependencies)
{
    var artifact = new PersonArtifact(udi)
    {
        Alias = person.Name,
        Name = person.Name,
        DepartmentId = person.Department.Id,
    };

    // Department node must exist to deploy the person.
    dependencies.Add(new ArtifactDependency(person.Department.GetUdi(), true, ArtifactDependencyMode.Exist));

    return artifact;
}

Value Connectors

As well as dependencies at the level of entities, we can also have dependencies in the property values as well. In Umbraco, an example of this is the multi-node tree picker property editor. It contains references to other content items, that should also be deployed along with the content that hosts the property itself.

Value connectors are used to track these dependencies and can also be used to transform property data as it is moved between environments.

The following illustrative example considers a property editor that stores the integer ID of an media item. The integer ID of a media item is not consistent between environments, so we'll need to transform it. And we also want to ensure that the related media item itself is transferred as well as the integer ID reference.

using Umbraco.Cms.Core.Deploy;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core;
using Microsoft.Extensions.Logging;
using Umbraco.Deploy.Core;
using Umbraco.Deploy.Core.Connectors.ValueConnectors;

namespace MyExtensions;

public class MyMediaPropertyValueConnector : ValueConnectorBase
{
    private readonly IEntityService _entityService;
    private readonly ILogger<MyMediaPropertyValueConnector> _logger;

    public MyMediaPropertyValueConnector(IEntityService entityService, ILogger<MyMediaPropertyValueConnector> logger)
    {
        _entityService = entityService;
        _logger = logger;
    }

    public override IEnumerable<string> PropertyEditorAliases => new[] { "MyMediaPropertyEditor" };

    public override string? ToArtifact(object? value, IPropertyType propertyType, ICollection<ArtifactDependency> dependencies, IContextCache contextCache)
    {
        var svalue = value as string;
        if (string.IsNullOrWhiteSpace(svalue))
        {
            return null;
        }

        if (!int.TryParse(svalue, out var intvalue))
        {
            return null;
        }

        Attempt<Guid> getKeyAttempt = _entityService.GetKey(intvalue, UmbracoObjectTypes.Media);

        if (getKeyAttempt.Success)
        {
            var udi = new GuidUdi(Constants.UdiEntityType.Media, getKeyAttempt.Result);
            dependencies.Add(new ArtifactDependency(udi, false, ArtifactDependencyMode.Exist));

            return udi.ToString();
        }
        else
        {
            _logger.LogDebug($"Couldn't convert integer value #{intvalue} to UDI");
        }

        return null;
    }

    public override object? FromArtifact(string? value, IPropertyType propertyType, object? currentValue, IContextCache contextCache)
    {
        if (string.IsNullOrWhiteSpace(value))
        {
            return null;
        }

        if (!UdiParser.TryParse(value, out GuidUdi? udi) || udi!.Guid == Guid.Empty)
        {
            return null;
        }

        Attempt<int> getIdAttempt = _entityService.GetId(udi.Guid, UmbracoObjectTypes.Media);

        if (!getIdAttempt.Success)
        {
            return null;
        }

        return getIdAttempt.Result.ToString();
    }
}

More examples of these can be found in the open-source Umbraco.Deploy.Contrib project.

Grid Cell Value Connector

The third and final type of connector is the grid cell value connector. These are responsible for converting values and tracking dependencies for grid editors.

Umbraco Deploy comes with connectors for the built-in editors such as for media and macros.

It's also possible to create your own, as in this example.

The following grid editor is an illustrative example for a rudimentary custom image picker. It contains a package mamifest file:

{
    "gridEditors": [
        {
            "name": "TestImagePicker",
            "alias": "testImagePicker",
            "view": "/App_Plugins/TestGridEditor/editor.html",
            "icon": "icon-code"
        }
    ]
}

And an editor view:

<div>
    <label>Enter The Integer Id Of An Image:</label>
    <input ng-model="control.value" type="number">
</div>

The value stored by the grid editor will be the integer Id of a media item.

When transferring this value to an upstream environment using Umbraco Deploy, these tasks are required:

  • The integer Id needs to be converted to a Guid for transfer. Guids for content and media are the same across environments but integer Ids will differ.

  • On creation in the upstream environment, the Guid value needs to be converted back to an integer for storage in the grid editor.

  • A dependency on the selected media item needs to be tracked, such that it will be transferred to the upstream environment along with the changes to the grid content.

We can implement that via a grid cell value connector. The following code is for Umbraco Deploy 10.1. For earlier versions, or from Umbraco Deploy 11, the base class should be GridCellValueConnectorBase.

using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Deploy;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Services;
using Umbraco.Deploy.Core;
namespace Umbraco.Deploy.Infrastructure.Connectors.GridCellValueConnectors
{
    public class CustomMediaGridCellValueConnector : GridCellValueConnectorBase2
    {
        public CustomMediaGridCellValueConnector(IEntityService entityService, ILocalLinkParser localLinkParser)
            : base(entityService, localLinkParser)
        {
        }
        public override bool IsConnector(string view) => string.Equals(view, "/App_Plugins/TestGridEditor/editor.html", StringComparison.OrdinalIgnoreCase);
        public override string? GetValue(GridValue.GridControl control, ICollection<ArtifactDependency> dependencies, IContextCache contextCache)
        {
            var value = control.Value?.ToString();
            if (string.IsNullOrEmpty(value))
            {
                return null;
            }
            if (!int.TryParse(value, out var valueAsInt))
            {
                return null;
            }
            Udi? mediaUdi = GetUdi(valueAsInt, UmbracoObjectTypes.Media);
            if (mediaUdi == null)
            {
                return null;
            }
            dependencies.Add(new ArtifactDependency(mediaUdi, false, ArtifactDependencyMode.Exist));
            return mediaUdi.ToString();
        }
        public override void SetValue(GridValue.GridControl control, IContextCache contextCache)
        {
            var value = control.Value?.ToString();
            if (string.IsNullOrWhiteSpace(value))
            {
                return;
            }
            var guidUdi = UdiParser.Parse(value.ToString() ?? string.Empty) as GuidUdi;
            if (guidUdi == null)
            {
                return;
            }
            var mediaId = GetNodeId(guidUdi);
            if (!mediaId.HasValue)
            {
                return;
            }
            control.Value = mediaId.Value;
        }
    }
}

Registration

With the artifact and connectors in place, the final step necessary is to register your entity for deployment.

Connectors do not need to be registered. The fact that they inherit from particular interfaces known to Umbraco Deploy is enough to ensure that they will be used.

Custom Entity Types

If custom entity types are introduced that will be handled by Umbraco Deploy, they need to be registered with Umbraco to parse the UDI references.

This is done via the following code, which can be triggered from a Umbraco component or an UmbracoApplicationStartingNotification handler.

UdiParser.RegisterUdiType("mypackage-example", UdiType.GuidUdi);

Disk Based Transfers

To deploy the entity as schema, via disk based representations held in .uda files, it's necessary to register the entity with the disk entity service. This is done in a component, where events are used to trigger a serialization of the entity to disk whenever one of them is saved.

public class ExampleDataDeployComponent : IComponent
{
    private readonly IDiskEntityService _diskEntityService;
    private readonly IServiceConnectorFactory _serviceConnectorFactory;
    private readonly IExampleDataService _exampleDataService;

    public ExampleDataDeployComponent(
        IDiskEntityService diskEntityService,
        IServiceConnectorFactory serviceConnectorFactory,
        IExampleDataService exampleDataService)
        {
            _diskEntityService = diskEntityService;
            _serviceConnectorFactory = serviceConnectorFactory;
            _exampleDataService = exampleDataService;
        }

    public void Initialize()
    {
        _diskEntityService.RegisterDiskEntityType("mypackage-example");
        _exampleDataService.ExampleSaved += ExampleOnSaved;
    }

    private void ExampleOnSaved(object sender, ExampleEventArgs e)
    {
        var artifact = GetExampleArtifactFromEvent(e);
        _diskEntityService.WriteArtifacts(new[] { artifact });
    }

    private IArtifact GetExampleArtifactFromEvent(ExampleEventArgs e)
    {
        var udi = e.Example.GetUdi();
        return _serviceConnectorFactory.GetConnector(udi.EntityType).GetArtifact(e.Example);
    }

    public void Terminate()
    {
    }
}

Including Plugin Registered Disk Entities in the Schema Comparison Dashboard

In Umbraco Deploy 9.4 a schema comparison feature was added to the dashboard available under Settings > Deploy. This lists the Deploy managed entities held in Umbraco and shows a comparison with the data held in the .uda files on disk.

All core Umbraco entities, such as Document Types and Data Types, will be shown.

To include entities from plugins, they need to be registered using a method overload as shown above, that allows to provide additional detail, e.g.:

_diskEntityService.RegisterDiskEntityType(
    "mypackage-example",
    "Examples",
    false,
    _exampleDataService.GetAll().Select(x => new DeployDiskRegisteredEntityTypeDetail.InstalledEntityDetail(x.GetUdi(), x.Name, x))));

The parameters are as follows:

  • The system name of the entity type (as used in the UdiDefinition attribute).

  • A human readable, pluralized name for display in the schema comparison dashboard user interface.

  • A flag indicating whether the entity is an Umbraco one, which should be set to false.

  • A function that returns all entities of the type installed in Umbraco, mapped to an object exposing the Udi and name of the entity.

Backoffice Integrated Transfers

If the optimal deployment workflow for your entity is to have editors control the deployment operations, the transfer entity service should be used. This would be instead of registering with the disk entity service. The process is similar, but a bit more involved. There's a need to also register details of the tree being used for editing the entities. In more complex cases, we also need to be able to handle the situation where multiple entity types are managed within a single tree.

An introduction to this feature can be found in the second half of this recorded session from Codegarden 2021.

There's also a code sample, demonstrated in the video linked above, available here.

The following code shows the registration of an entity for Backoffice deployment, where we have the simplest case of a single tree for the entity.

public class ExampleDataDeployComponent : IComponent
{
    private readonly ITransferEntityService _transferEntityService;

    public ExampleDataDeployComponent(
        ITransferEntityService transferEntityService)
    {
        _transferEntityService = transferEntityService;
    }

    public void Initialize()
    {
        _transferEntityService.RegisterTransferEntityType(
            "mypackage-example",
            "Examples",
            new DeployRegisteredEntityTypeDetailOptions
            {
                SupportsQueueForTransfer = true,
                SupportsQueueForTransferOfDescendents = true,
                SupportsRestore = true,
                PermittedToRestore = true,
                SupportsPartialRestore = true,
            },
            false,
            "exampleTreeAlias",
            (string routePath, HttpContext httpContext) => true,
            (string nodeId, HttpContext httpContext) => true,
            (string nodeId, HttpContext httpContext, out Guid entityId) => Guid.TryParse(nodeId, out entityId),
            new DeployRegisteredEntityTypeDetail.RemoteTreeDetail(FormsTreeHelper.GetExampleTree, "example", "externalExampleTree"));
    }

    public void Terminate()
    {
    }
}

The RegisterTransferEntityType method on the ITransferEntityService takes the following parameters:

  • The name of the entity type, as configured in the UdiDefinition attribute associated with your custom service connector.

  • A pluralized, human-readable name of the entity, which is used in the transfer queue visual presentation to users.

  • A set of options, allowing configuration of whether different deploy operations like queue for transfer and partial restore are made available from the tree menu for the entity.

  • A value indicating whether the entity is an Umbraco entity, queryable via the IEntityService. For custom solutions and packages, the value to use here is always false.

  • The alias of the tree used for creating and editing the entity data.

We then have three functions, which are used to determine if the registered entity matches a specific node and tree alias. For trees managing single entities as we have here, we know that all nodes related to that tree alias will be for the registered entity. And that each node Id is the Guid identifier for the entity. Hence we can use the following function definitions:

  • Return true for all route paths.

  • Return true for all node Ids.

  • Return true and parse the Guid identity value from the provided string.

For more complex cases we need the means to distinguish between entities. An example could be when a tree manages more than one entity type. Here we would need to identify whether the entity is being referenced by a particular route path or node ID. A common way to handle this is to prefix the GUID identifier with a different value for each entity. It can then be used to determine to which entity the value refers.

For example, as shown in the linked sample and video, we have entities for "Team" and "Rider", both managed in the same tree. When rendering the tree, a prefix of "team-" or "rider-" is added to the Guid identifier for the team or rider respectively. We then register the following functions, firstly for the team entity registration:

_transferEntityService.RegisterTransferEntityType(
    ...
    "teams",
    (string routePath, HttpContext httpContext) => routePath.Contains($"/teamEdit/") || routePath.Contains($"/teamsOverview"),
    (string nodeId, HttpContext httpContext) => nodeId == "-1" || nodeId.StartsWith("team-"),
    (string nodeId, HttpContext httpContext, out Guid entityId) => Guid.TryParse(nodeId.Substring("team-".Length), out entityId);

And then for the rider:

_transferEntityService.RegisterTransferEntityType(
    ...
    "teams",
    (string routePath) => routePath.Contains($"/riderEdit/"),
    (string nodeId) => nodeId.StartsWith("rider-"),
    (string nodeId, HttpContext httpContext, out Guid entityId) => Guid.TryParse(nodeId.Substring("rider-".Length), out entityId);

If access to services is required when parsing the entity ID, where the HttpContext is provided as a parameter, a service can be retrieved. For example:

var localizationService = httpContext.RequestServices.GetRequiredService<ILocalizationService>();

The HttpContext parameter for the matchesRoutePath and matchesNodeId functions was added in Deploy 11. Before that version, it is necessary to use the StaticServiceProvider.Instance to access registered services or the HttpContext.

Finally, the remoteTree optional parameter adds support for plugins to implement Deploy's "partial restore" feature. This gives the editor the option to select an item to restore, from a tree picker displaying details from a remote environment. The parameter is of type DeployRegisteredEntityTypeDetail.RemoteTreeDetail that defines three pieces of information:

  • A function responsible for returning a level of a tree.

  • The name of the entity (or entities) that can be restored from the remote tree.

  • The remote tree alias.

An example function that returns a level of a remote tree may look like this:

public static IEnumerable<RemoteTreeNode> GetExampleTree(string parentId, HttpContext httpContext)
{
    var exampleDataService = httpContext.RequestServices.GetRequiredService<IExampleDataService>();
    var items = exampleDataService.GetItems(parentId);
    return items
        .Select(x => new RemoteTreeNode
        {
            Id = x.Id,,
            Title = x.Name,
            Icon = "icon-box",
            ParentId = parentId,
            HasChildren = true,
        })
        .ToList();
}

To complete the setup for partial restore support, an external tree controller needs to be added, attributed to match the registered tree alias. Using a base class available in Umbraco.Deploy.Forms.Tree, this can look like the following:

[Tree(DeployConstants.SectionAlias, "externalExampleTree", TreeUse = TreeUse.Dialog)]
public class ExternalDataSourcesTreeController : ExternalTreeControllerBase
{
    public ExternalDataSourcesTreeController(
        ILocalizedTextService localizedTextService,
        UmbracoApiControllerTypeCollection umbracoApiControllerTypeCollection,
        IEventAggregator eventAggregator,
        IExtractEnvironmentInfo environmentInfoExtractor,
        LinkGenerator linkGenerator,
        ILoggerFactory loggerFactory,
        IOptions<DeploySettings> deploySettings)
        : base(localizedTextService, umbracoApiControllerTypeCollection, eventAggregator, environmentInfoExtractor, linkGenerator, loggerFactory, deploySettings, "mypackage-example")
    {
    }
}

Client-Side Registration

Most features that are available for the deployment of Umbraco entities will also be accessible to entities defined in custom solutions or packages. The "Transfer Now" option available from "Save and Publish" or "Save" button for content/media is only available to custom entities if requested client-side.

You would do this in the custom AngularJS controller responsible for handling the edit operations on your entity. Inject the pluginEntityService and calling the addInstantDeployButton function as shown in the following stripped down sample (for the full code, see the sample data repository linked above):

(function () {
    "use strict";

    function MyController($scope, $routeParams, myResource, formHelper, notificationsService, editorState, pluginEntityService) {

        var vm = this;

        vm.page = {};
        vm.entity = {};
        ...

        vm.page.defaultButton = {
            alias: "save",
            hotKey: "ctrl+s",
            hotKeyWhenHidden: true,
            labelKey: "buttons_save",
            letter: "S",
            handler: function () { vm.save(); }
        };
        vm.page.subButtons = [];

        function init() {

            ...

            if (!$routeParams.create) {

                myResource.getById($routeParams.id).then(function (entity) {

                    vm.entity = entity;

                    // Augment with additional details necessary for identifying the node for a deployment.
                    vm.entity.metaData = { treeAlias: $routeParams.tree };

                    ...
                });
            }

            pluginEntityService.addInstantDeployButton(vm.page.subButtons);
        }

        ...

        init();

    }

    angular.module("umbraco").controller("MyController", MyController);

})();

Refreshing Signatures

Umbraco Deploy improves the efficiency of transfers by caching signatures of each artifacts in the database for each environment. The signature is a string based, hashed representation of the serialized artifact. When an update is made to an entity, this signature value should be refreshed.

Hooking this up can be achieved by applying code similar to the following, extending the ExampleDataDeployComponent shown above.

public class ExampleDataDeployComponent : IComponent
{
    ...
    private readonly ISignatureService _signatureService;

    public ExampleDataDeployComponent(
    ...
    ISignatureService signatureService)
    {
        _signatureService = signatureService;
    }

    public void Initialize()
    {
        ...
        _signatureService.RegisterHandler<ExampleDataService, ExampleEventArgs>(nameof(IExampleDataService.ExampleSaved), (refresher, args) => refresher.SetSignature(GetExampleArtifactFromEvent(args)));
    }

    ...
}