Sitecore 10.1 introduced a great new feature for local development with containers: development-only configuration. This feature allows you to apply config transformations to your solution for local development only, without affecting your sites in production. Some examples of this are setting customErrors="Off" or compilation debug="true" in the Web.config.

As always with Sitecore, this feature is extensible and you can write your own development-only configurations if the out-of-the-box patches don't cover all of your needs. In this post I'll show you how to add your own configurations.

TL;DR

All of the code for this tutorial is on GitHub: https://github.com/coreyasmith/sitecore-docker-dev-only-configs.

Sitecore 10.0

Although development-only configurations were introduced in Sitecore 10.1, if your solution is still on Sitecore 10.0 Initial Release, Update-1, or Update-2, you're in luck. Check out my blog post on backporting development-only configurations to Sitecore 10 and come back here to add some custom patches.

How It Works

Your CM and CD images copy the tools folder from the Sitecore Docker Tools Assets image as shown in this excerpt:

ARG TOOLING_IMAGE

FROM ${TOOLING_IMAGE} as tooling
FROM ${BASE_IMAGE}

# Copy development tools and entrypoint
COPY --from=tooling \tools\ \tools\

The tools folder contains out-of-the-box development-only configuration patches in a folder called dev-patches and the entrypoint for the CM and CD images. When the CM and CD containers start, the entrypoint looks at the SITECORE_DEVELOPMENT_PATCHES environment variable and applies the corresponding patches from the dev-patches folder to the web root.

Files with the .xdt extension are applied as transforms (e.g., Web.config.xdt -> Web.config), and .config files are copied into the web root as is.

Adding custom patches is as easy as adding new folders to tools\dev-patches in a custom Sitecore Docker Tools image and updating the SITECORE_DEVELOPMENT_PATCHES environment variable with the names of the custom patch folders.

Custom Tools Image

The first step is to create a custom tools image. Create a folder for your tools image (e.g., \docker\build\tools) in your repository. Within, create a new Dockerfile and a folder called dev-patches. The Dockerfile is simple:

# escape=`

ARG BASE_IMAGE

FROM ${BASE_IMAGE}

COPY dev-patches\ \tools\dev-patches\

Update your docker-compose.yml (or docker-compose.override.yml) to build your custom tools image:

services:
  tools:
    image: ${REGISTRY}${COMPOSE_PROJECT_NAME}-sitecore-docker-tools-assets:${VERSION:-latest}
    build:
      context: ./docker/build/tools
      args:
        BASE_IMAGE: ${SITECORE_TOOLS_REGISTRY}sitecore-docker-tools-assets:${TOOLS_VERSION}
    scale: 0

And update your CM/CD containers to use your custom tools image instead of Sitecore's:

services:
  cd:
    build:
      args:
        TOOLING_IMAGE: ${REGISTRY}${COMPOSE_PROJECT_NAME}-sitecore-docker-tools-assets:${VERSION:-latest}
    depends_on:
      - tools
    environment:
      SITECORE_DEVELOPMENT_PATCHES: ${SITECORE_DEVELOPMENT_PATCHES}
  cm:
    build:
      args:
        TOOLING_IMAGE: ${REGISTRY}${COMPOSE_PROJECT_NAME}-sitecore-docker-tools-assets:${VERSION:-latest}
    depends_on:
      - tools
    environment:
      SITECORE_DEVELOPMENT_PATCHES: ${SITECORE_DEVELOPMENT_PATCHES}

Now you have all of the infrastructure in place to create custom patches.

Custom Patches

We will make two custom patches: one that demonstrates transforms, and one that demonstrates regular Sitecore config patches.

Transform Patches

In the \docker\build\tools folder, create a folder called MyCustomTransforms. In that folder, create two files:

Web.config.xdt (i.e., \docker\build\tools\MyCustomTransforms\Web.config.xdt). Contents:

<?xml version="1.0" encoding="utf-8"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
  <appSettings>
    <add key="MyTransformedSetting"
         value="MyTransformedSetting"
         xdt:Transform="InsertIfMissing"
         xdt:Locator="Match(key)" />
  </appSettings>
</configuration>

\App_Config\ConnectionStrings.config.xdt (i.e., \docker\build\tools\MyCustomTransforms\App_Config\ConnectionStrings.config.xdt). Contents:

<?xml version="1.0" encoding="utf-8"?>
<connectionStrings xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
  <add name="MyTransformedConnectionString"
       connectionString="MyTransformedConnectionString"
       xdt:Transform="InsertIfMissing"
       xdt:Locator="Match(name)" />
</connectionStrings>

Now add MyCustomTransforms to the SITECORE_DEVELOPMENT_PATCHES environment variable (e.g., in your .env file). Rebuild your CM/CD containers and recreate them (can be done in one command with docker-compose up -d --build). You should be able to see the custom app setting and connection string if you exec into the containers and do Get-Content on the Web.config and App_Config\ConnectionStrings.config.

⚠️Note⚠️: the name and location of transforms (.xdt) is important. The folder structure of patch folders mirrors the web root. To transform Web.config, Web.config.xdt must be at the root of the patch folder (i.e., \docker\build\tools\MyCustomPatch\Web.config.xdt) since Web.config is located at the root of the web root. To transform ConnectionStrings.config, the transform must be at \docker\build\tools\MyCustomPatch\App_Config\ConnectionStrings.config.xdt since ConnectionStrings.config is in the App_Config folder of the web root.

Sitecore Config Patches

In the \docker\build\tools folder, create a folder called MyCustomPatch. In that folder, create \App_Config\Environment\MyCustomPatch.config (i.e., \docker\build\tools\MyCustomPatch\App_Config\Environment\MyCustomPatch.config). Contents:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <sitecore>
    <settings>
      <setting name="MyCustomSetting"
               value="MyCustomSetting" />
    </settings>
  </sitecore>
</configuration>

Now add MyCustomPatch to the SITECORE_DEVELOPMENT_PATCHES environment variable (e.g., in your .env file), and rebuild your CM/CD containers (docker-compose up -d --build). Your custom Sitecore setting should be visible from /sitecore/admin/ShowConfig.aspx.

⚠️Note⚠️: at the moment this only works for files with the .config extension.

Detailed HTTP Errors

A practical development-only config that you may want to add is one that sets httpErrors to Detailed in the Web.config. Sitecore ships a patch that sets customErrors to Off for local development, but customErrors doesn't cover all errors. The default mode for httpErrors, DetailedLocalOnly, means that with Docker in particular, some errors will not show a full stack trace. This is an easy fix.

In the \docker\build\tools folder, create a folder called HttpErrorsDetailed. In that folder, create Web.config.xdt (i.e., \docker\build\tools\HttpErrorsDetailed\Web.config.xdt). Contents:

<?xml version="1.0" encoding="utf-8"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
  <system.webServer>
    <httpErrors xdt:Transform="InsertIfMissing" />
    <httpErrors errorMode="Detailed"
                xdt:Transform="SetAttributes" />
  </system.webServer>
</configuration>

Now add HttpErrorsDetailed to the SITECORE_DEVELOPMENT_PATCHES environment variable (e.g., in your .env file), and rebuild your CM/CD containers (docker-compose up -d --build). Done.

I've submitted a pull request to Sitecore for this patch, so hopefully it's included by default in future versions of the Sitecore Docker Tools.

Conclusion

Development-only configurations are a handy way to apply config patches to only your local environment when running Sitecore on Docker. In this post I've demonstrated how you can apply XDT transforms to configs in the Sitecore web root, and also copy in Sitecore config patches. Although it's generally best to keep your development-only configurations small and atomic, as shown here, you can mix and match XDT transforms and configs in the same patch if you like.

A big thanks to Nick "techphoria414" Wesselman and his team for adding this feature to Sitecore Docker Tools.

Nick Wesselman and me at Sitecore Symposium in Las Vegas, 2017

Thanks to mon ami Jean-François L'Heureux for reviewing this post.