---
title: "Build Sitecore solutions"
slug: "build-sitecore-solutions"
abstract: "Explains how you build Sitecore solutions."
---
# Build Sitecore solutions

This topic describes the Dockerfile and the Docker image build process and how you use it to build your Sitecore solution.

If you have not already done so, clone the [Docker Examples repository](https://github.com/Sitecore/docker-examples) to a location on your machine. In this topic, we use the *custom-images* folder. This topic assumes that you have gone through the documentation on how to [run an out-of-the-box Sitecore instance](https://doc.sitecore.com/xp/en/developers/104/developer-tools/run-your-first-sitecore-instance.html "Run your first Sitecore instance") and that you can successfully start a Sitecore instance.

This topic shows how you build container images with your solution code. To ensure efficient feedback loops during development, you must also configure your development environment for [deploying files into running containers](https://doc.sitecore.com/xp/en/developers/104/developer-tools/deploying-files-into-running-containers.html "Deploying files into running containers").

<details>
<summary><h2>About Dockerfiles</h2></summary>

You write a Dockerfile as the first step in containerizing your application. A Dockerfile contains instructions that Docker uses to assemble a Docker image and run it. The Dockerfile commands are a step-by-step recipe for how to build up your image.

The following is a Dockerfile example for a simple (non-Sitecore) ASP.NET MVC app:

```

FROM mcr.microsoft.com/dotnet/framework/sdk:4.8 AS build
WORKDIR /app

COPY *.sln .
COPY aspnetmvcapp/*.csproj ./aspnetmvcapp/
RUN nuget restore

COPY aspnetmvcapp/. ./aspnetmvcapp/
WORKDIR /app/aspnetmvcapp
RUN msbuild /p:Configuration=Release

FROM mcr.microsoft.com/dotnet/framework/aspnet:4.8 AS runtime
WORKDIR /inetpub/wwwroot
COPY --from=build /app/aspnetmvcapp/. ./

```

This example uses a [multi-stage build](https://docs.docker.com/develop/develop-images/multistage-build/): first the code is built with the `mcr.microsoft.com/dotnet/framework/sdk` image (the `build` stage), and then the output is copied to the `mcr.microsoft.com/dotnet/framework/aspnet` image (the `runtime` stage).

The Dockerfile is then used by the [Docker build command](https://docs.docker.com/engine/reference/commandline/build/) and this command builds and creates the image.

An optional `[.dockerignore](https://docs.docker.com/engine/reference/builder/#dockerignore-file)` can be used to exclude files and folders from the build context, reducing the size or skipping sensitive data in `COPY` and `ADD` commands.

The example shows that code compilation and build are part of a Dockerfile's instructions. In .NET, this could include a NuGet restore, followed by invoking MSBuild. Building your application directly in a Dockerfile like this has advantages over a more traditional build, including:

- Portability - The entire build process is containerized. Build agents and local environments do not need to have anything installed other than Docker.
- Control over the build environment - The solution owns which build dependencies (and which versions) are used.
- Efficiency - Even if build steps are very verbose, use of the Docker build cache optimizes rebuilds.
- Plays nice in Docker ecosystem - Builds can be triggered using Docker commands and retrieving build artifacts for use in other images is simple with Dockerfile `FROM` instructions.

> [!note]
> This topic focuses on using a Dockerfile. Although building in a Dockerfile is preferred, but you might have to [rely on traditional means to build your solution](https://doc.sitecore.com/xp/en/developers/104/developer-tools/building-custom-sitecore-images.html "Building custom Sitecore images") (for example because of the limitations of a legacy codebase or build process).

</details>

<details>
<summary><h2>Solution build Dockerfile and image</h2></summary>

With a typical Sitecore implementation, a single Visual Studio solution usually creates build artifacts for multiple roles, for example, Website and XConnect assemblies, and some artifacts must be deployed to multiple roles (for example CM/CD). For containers, this means that the same build output must be layered on top of *multiple base Sitecore runtime images*. You could instead duplicate the build instructions for each Sitecore image, but this would be very inefficient.

What you need is a Dockerfile that is focused solely on building your solution and storing the output as structured build artifacts on the resulting image.

### Build Dockerfile

The root `Dockerfile` in the example is such a Dockerfile. The Docker community often name this type of build Dockerfile `Dockerfile.build`.

Navigate to the *custom-images* folder, and look at the `Dockerfile` located there. Note that for simplicity, the `BASE_IMAGE` and `BUILD_IMAGE` `ARG`s have been expanded:

1. The file starts with an [escape directive](https://docs.docker.com/engine/reference/builder/#escape) to set the escape character to a backtick (\`), instead of the default backslash:

    ```text
    # escape=`
    ```

2. A `prep` stage is used to gather only artifacts necessary for NuGet restore. This is a common optimization made in .NET builds (see [Dockerfile best practices](https://doc.sitecore.com/xp/en/developers/104/developer-tools/dockerfile-best-practices-and-scenarios.html "Dockerfile best practices and scenarios") for an explanation):

    ```

    FROM mcr.microsoft.com/dotnet/framework/sdk:4.8 AS prep

    COPY *.sln nuget.config Directory.Build.targets Packages.props \nuget\
    COPY src\ \temp\
    RUN Invoke-Expression 'robocopy C:\temp C:\nuget\src /s /ndl /njh /njs *.csproj *.scproj packages.config'
    ```

3. A new `builder` stage initiates the code compilation and build process, based on the [.NET Framework SDK image](https://hub.docker.com/_/microsoft-dotnet-framework-sdk/), and a `BUILD_CONFIGURATION` `ARG` is declared (this is either `debug` or `release`, configured in Docker Compose):

    ```

    FROM mcr.microsoft.com/dotnet/framework/sdk:4.8 AS builder
    ARG BUILD_CONFIGURATION
    ```

4. The [`SHELL` instruction](https://docs.docker.com/engine/reference/builder/#shell) switches the default shell to PowerShell (from the default of `cmd`) for all subsequent instructions. This is a common instruction in Windows Dockerfiles:

    ```text
    SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"]
    ```

5. Next, a working directory is created, the NuGet artifacts collected earlier are copied in, and a (optimized) `nuget restore` is performed:

    ```

    WORKDIR C:\build
    COPY --from=prep .\nuget .\
    RUN nuget restore
    ```

6. After the restore, the remainder of the source code is copied in, and transform files are collected at `C:\out\transforms`:

    ```

    COPY src\ .\src\
    RUN Invoke-Expression 'robocopy C:\build\src C:\out\transforms /s /ndl /njh /njs *.xdt'
    ```

    The example includes a [`.dockerignore`](https://docs.docker.com/engine/reference/builder/#dockerignore-file) (located alongside the Dockerfile). This reduces the size of the `COPY` commands and excludes things like `bin` and `obj` folders. This is the best practice for build Dockerfiles. For more information about config transforms, see [Applying configuration transforms](https://doc.sitecore.com/xp/en/developers/104/developer-tools/applying-configuration-transforms.html "Applying configuration transforms").

7. Next, the build is performed for the configured `BUILD_CONFIGURATION` using `msbuild`. The example contains projects targeting both the website/platform (*DockerExamples.Website.csproj*) and xConnect (*DockerExamples.XConnect.csproj*) environments. A simple file system publish is used, with the output landing at `C:\out\website` and `C:\out\xconnect` respectively:

    ```

    RUN msbuild .\src\DockerExamples.Website\DockerExamples.Website.csproj /p:Configuration=$env:BUILD_CONFIGURATION /p:DeployOnBuild=True /p:DeployDefaultTarget=WebPublish /p:WebPublishMethod=FileSystem /p:PublishUrl=C:\out\website
    RUN msbuild .\src\DockerExamples.XConnect\DockerExamples.XConnect.csproj /p:Configuration=$env:BUILD_CONFIGURATION /p:DeployOnBuild=True /p:DeployDefaultTarget=WebPublish /p:WebPublishMethod=FileSystem /p:PublishUrl=C:\out\xconnect
    ```

8. After the build is completed, the build output for the final image is collected. For this stage, the [Microsoft Nano Server image](https://hub.docker.com/_/microsoft-windows-nanoserver) is used. Because this image only delivers files and is never run, the base image is selected for its optimized size - *much* smaller than other runtime images:

    ```text
    FROM mcr.microsoft.com/windows/nanoserver:1809
    ```

9. The output files are copied in from the `builder` stage to our final image with the following structure:
    - `\artifacts\website`
    - `\artifacts\transforms`
    - `\artifacts\xconnect`

    ```

    WORKDIR C:\artifacts
    COPY --from=builder C:\out\website .\website\
    COPY --from=builder C:\out\transforms .\transforms\
    COPY --from=builder C:\out\xconnect .\xconnect\
    ```

> [!note]
> This example does not do Sitecore item serialization. Depending on your serialization framework and strategy, your solution build Dockerfile can have additional instructions. See [Deploying items](https://doc.sitecore.com/xp/en/developers/104/developer-tools/deploying-items.html "Deploying items") for details.

### Solution image

The solution build Dockerfile produces an image that consists only of build artifacts. The resulting *solution image* is never intended to be run in a Docker container. Such images are sometimes called *asset images*.

</details>

<details>
<summary><h2>Configure in Docker Compose</h2></summary>

You must send a Dockerfile through the [Docker build command](https://docs.docker.com/engine/reference/commandline/build/) to produce an image. You can certainly use `build` command directly, but it is mostly configured with [Docker Compose](https://docs.docker.com/compose/).

The *custom-images* folder contains the following files:

- `.env`
- `docker-compose.yml`
- `docker-compose.override.yml`

These are all types of Docker Compose files.

### Understand docker-compose.override.yml

For any Docker Compose command (such as `docker-compose up -d`), the `docker-compose.override.yml` file is automatically included along with your main `docker-compose.yml` file, unless you specify otherwise. When Docker Compose is handed two or more compose files, it merges them together, bringing all the resources and configuration together into a single merged definition.

In this example, the `docker-compose.yml` file is the default *Sitecore Experience Platform - Single (XP0)* Docker Compose file that comes from Sitecore. The `docker-compose.override.yml` extends the main file with overrides and extensions necessary for custom Sitecore image build and development purposes.

### Configure the solution service

The `docker-compose.override.yml` file is where you define the solution image build.

Open the file and look at the `solution` service to see how it is configured:

```

solution:
  image: ${REGISTRY}${COMPOSE_PROJECT_NAME}-solution:${VERSION:-latest}
  build:
    context: .
    args:
      BASE_IMAGE: ${SOLUTION_BASE_IMAGE}
      BUILD_IMAGE: ${SOLUTION_BUILD_IMAGE}
      BUILD_CONFIGURATION: ${BUILD_CONFIGURATION}
  scale: 0

```

Note the following points:

- Variable values (for example, `${SOLUTION_BASE_IMAGE}`) are defined in the [environment file](https://docs.docker.com/compose/env-file/) (`.env`) in this example, but can also be sourced from system environment variables on local development machines or secrets on your build server.
- The image name uses a `-solution` suffix. With the default variable values, the tagged version is `docker-examples-solution:latest`
- The `build` `context` is set to `.` to tell Docker Compose to use the build Dockerfile at the same location.
- The `build` `args` correlate to those found in the build Dockerfile.
- `scale` is set to 0 so that a container for the `solution` service is not started during a `docker-compose up`.

</details>

<details>
<summary><h2>Build the solution image</h2></summary>

To build the solution image:

1. Open a PowerShell prompt and run the following from the same folder as your Compose files:

    ```text
    docker-compose build solution
    ```

    This initiates the build process for the solution image and creates your image:

    ```

    Building solution
    Step 1/21 : ARG BASE_IMAGE
    Step 2/21 : ARG BUILD_IMAGE
    Step 3/21 : FROM ${BUILD_IMAGE} AS prep
    [...]
    Successfully built 9bb20b2ab6db
    Successfully tagged docker-examples-solution:latest
    ```

2. Confirm the image was created by listing all Docker images:

    ```text
    docker images docker-examples*
    ```

    ```

    REPOSITORY                TAG     IMAGE ID      CREATED        SIZE
    docker-examples-solution  latest  9bb20b2ab6db  2 minutes ago  259MB
    ```

</details>

<details>
<summary><h2>Troubleshoot solution image builds</h2></summary>

Start by looking at the [troubleshooting guide](https://doc.sitecore.com/xp/en/developers/104/developer-tools/troubleshooting-docker.html "Troubleshooting Docker").

One common troubleshooting problem unique to the solution image (or any *asset image*) is that because it is never run as a container, it might not be obvious how you can explore the resulting file system. You can do this by running the image with an interactive shell.

For example, to open up an interactive command prompt (Nano Server does not have PowerShell) to the solution image example given previously:

```text
docker run -it --rm docker-examples-solution:latest

```

Type `exit` to remove the temporary container and return to your previous PowerShell session.

</details>

<details>
<summary><h2>Further reading</h2></summary>

- [Dockerfile reference](https://docs.docker.com/engine/reference/builder/)
- [Dockerfile on Windows](https://docs.microsoft.com/en-us/virtualization/windowscontainers/manage-docker/manage-windows-dockerfile)
- [Dockerfile best practices and scenarios](https://doc.sitecore.com/xp/en/developers/104/developer-tools/dockerfile-best-practices-and-scenarios.html "Dockerfile best practices and scenarios")

</details>