- [Home page](https://www.brimit.com/)
- [Blog](https://www.brimit.com/blog)

# Optimizing Sitecore Builds: CI/CD Performance Tips

[Tech Talks](https://www.brimit.com/blog?categories=Tech%20Talks) [Sitecore](https://www.brimit.com/blog?platforms=Sitecore)
[Igor Zharikov](https://www.brimit.com/blog/author?authors=Igor%20Zharikov) on October 6, 2025

![CI/CD Optimization in Sitecore](https://www.brimit.com/-/jssmedia/images/blog/sitecore/ci-cd-optimization/logo.png?h=1005&iar=0&w=1704&hash=985ACD127177F4BED8C671E85F0CDE1E)

Building and deploying Sitecore solutions can be time-consuming if pipelines aren’t optimized. This article shares practical techniques we used to speed up CI/CD workflows for Sitecore XP (Kubernetes in our case) deployments, enabling faster and more efficient delivery.

#### In short

If you don’t want to read all the details, here are the main principles that can be applied to any CI/CD pipeline:

- Do only what’s necessary — remove redundant tasks.
- Use caching (`node_modules`, NuGet, etc.).
- Reduce I/O load (e.g., file copies) — minimize the number of file transfers.

But… if you’re still interested in the details, read on.

*Note*: All implementation details here are for Azure DevOps pipelines, but the same principles apply to any CI/CD platform.

* * *

#### Run tasks conditionally

Our build pipeline is shared between regular builds (triggered on push) and deployment builds (used when deploying to an environment and generating deployment artifacts).

*Note*: We distinguish between those builds using the `manual_release` parameter. When it’s `true` (or checked), it triggers the next steps — image creation and Kubernetes deployment.

The simplest approach is to run certain steps conditionally:

- Copy deployment-only files: e.g., Unicorn serialization files or configuration transforms.
- Create and publish artifacts: `ArchiveFiles@2`, `PublishBuildArtifacts@1`
- Publish debug symbols: `PublishSymbols@2`

Example:

```
- task: ArchiveFiles@2
  displayName: Zip Artifact Website
  ...
  condition: eq(variables.buildMode, 'Full') # execute this task only if buildMode is Full
```

*Note*: This optimization improves the average build performance by skipping unnecessary tasks during most builds (though it doesn’t affect worst-case build times).

**Result**: around 3–4 minutes faster per push-triggered build.

* * *

#### Caching

Caching is one of the most effective optimization techniques. With proper configuration, it can significantly improve performance.

##### Pipeline caching

[Pipeline caching](https://learn.microsoft.com/en-us/azure/devops/pipelines/release/caching) in Azure DevOps can be implemented using the [Cache@2](https://learn.microsoft.com/en-us/azure/devops/pipelines/tasks/reference/cache-v2?view=azure-pipelines) task.

Useful cache targets include:

- `node_modules` — if the cache restores successfully, there’s no need to reinstall packages.
- The `packages` folder for NuGet — `nuget restore` still runs, but much faster.

Example:

```
- task: Cache@2
  displayName: node_modules Cache
  inputs:
    key: 'node_modules | "$(Agent.OS)" | frontend/package-lock.json'
    path: "frontend/node_modules"
    cacheHitVar: NODE_MODULES_CACHE_RESTORED

- task: Npm@1
  displayName: npm ci
  inputs:
    command: "ci"
    workingDir: "frontend"
  condition: ne(variables.NODE_MODULES_CACHE_RESTORED, 'true')

# just cache and restore Nuget packages fodler
- task: Cache@2
  inputs:
    key: 'nuget | "$(Agent.OS)" | Packages.props | nuget.config'
    path: packages
  displayName: Cache NuGet packages
```

*Explanation*: The `cacheHitVar` input sets `NODE_MODULES_CACHE_RESTORED` to `true` if the cache was restored.

Then the `npm ci` task only runs when the cache wasn’t restored — meaning no redundant package installation.

##### Frontend caching

Use filesystem caching to speed up continuous builds. In our case, we configured [Webpack build cache](https://webpack.js.org/configuration/cache/).

```
const config = {
  ...,
  cache: {
    type: 'filesystem',
    name: '[PROJECT_NAME]',
    cacheDirectory: resolve(__dirname, 'node_modules', '.cache'),
    buildDependencies: {
      config: [__filename],
    },
  },
};
```

*Note*: The cache directory is stored inside `node_modules`, which means when the `node_modules` folder is restored from pipeline cache, Webpack can reuse its stored cache — resulting in **faster local and CI/CD builds**.

**Result**: Frontend build time (`npm install` + build) reduced from an average of 10 minutes to 3 minutes.

* * *

#### IO Operations

Our CI/CD setup uses a **pipeline chain** consisting of several stages:

**Build → Solution Image → CM/CD Builds.**

During this process, Unicorn serialization items must be included in the Docker images. This introduces a heavy I/O load, as a large number of `.yaml` files are copied between stages.

The flow looks like this:

| # | Step | Action |
| --- | --- | --- |
| 1 | **Build** | Create an **`items` artifact** that contains all serialized Unicorn items. |
| 2 | **Solution Image** | 1. Extract the artifact.<br>
            2. Copy all `.yaml` files into the Docker image. |
| 3 | **CM & CD Builds** | Copy the `.yaml` files from the Solution image into the final CM and CD images. |

Each stage involves file extraction and copying, leading to repeated I/O operations and slower overall build performance — especially when dealing with large numbers of serialized items.

**Previously**, it looked like this:

*Pipeline*:

```
- task: ExtractFiles@1
  displayName: Extract Artifact | Website
  inputs:
    archiveFilePatterns: $(Pipeline.Workspace)\build\$(artifact_prefix)_Website\*.zip
    destinationFolder: $(Build.SourcesDirectory)\backend\docker\build\solution.prebuild\artifacts\website
```

*Solution Dockerfile* — copying items from the extracted artifact into the image.

```
...
WORKDIR c:\prebuild
COPY artifacts\ .
RUN `
    Invoke-Expression 'robocopy C:\prebuild\website\App_Data\unicorn\src C:\out\items /s /ndl /nfl /njh /njs /nooffload /np *.yml'; `
...
```

*CM Dockerfile* — copying from the prebuild solution image into the CM image.

```
...
# Copy serialized items and Unicorn sync script
COPY --from=solution \artifacts\items\ \items\
...
```

This means there were **a lot of copy operations**.

The image build took **up to 20 minutes** due to the heavy I/O load from copying thousands of files.

The solution was to optimize it.

**After optimization**, it now looks like this:

```
- task: CopyFiles@2
  displayName: Copy Artifact | Website
  inputs:
    SourceFolder: $(Pipeline.Workspace)\build\$(artifact_prefix)_Website
    Contents: '*.zip'
    TargetFolder: $(Build.SourcesDirectory)\backend\docker\build\solution.prebuild\artifacts\website
```

*Solution Dockerfile* — just copy the zip archive into the Docker image.

```
...
WORKDIR c:\archives
COPY artifacts .
...
```

*CM Dockerfile* — keep the old copying for compatibility with local builds, but extract the zip if it’s a CI/CD build.

```
# Copy serialized items and Unicorn sync script
COPY --from=solution \artifacts\items\ \items\
# Extract archives
RUN if (Test-Path C:\archives\items.zip) { Invoke-Expression 'tar -xf C:\archives\items.zip -C C:\items' }
```

**Result**:

- Solution image build time reduced **from 20 minutes to 1 minute**.
- CM image build time reduced **from 20 minutes to 10 minutes**.

* * *

#### Conclusion

I hope the ideas described here help you optimize your CI/CD pipelines and reduce build times.

###### Author

![Igor Zharikov - Senior Sitecore Developer, Sitecore MVP](https://www.brimit.com/-/jssmedia/feature/blogs/authors/igor-zharikov-2.jpg?h=700&iar=0&w=700&hash=292A84E8CB3E5CE57CA743385CFB1464)

Igor Zharikov

Sitecore MVP / Senior Sitecore Developer
[Igor Zharikov](https://www.brimit.com/blog/author?authors=Igor%20Zharikov)

###### More By Categories

[#Events](https://www.brimit.com/blog?categories=#Events) [#How-to](https://www.brimit.com/blog?categories=#How-to) [#News](https://www.brimit.com/blog?categories=#News) [#Guides](https://www.brimit.com/blog?categories=#Guides)

###### More by Platform

[Data and AI](https://www.brimit.com/blog?platforms=Data%20and%20AI) [DXP](https://www.brimit.com/blog?platforms=DXP) [E-commerce](https://www.brimit.com/blog?platforms=E-commerce) [Internet of Things](https://www.brimit.com/blog?platforms=Internet%20of%20Things) [Sales and marketing automation](https://www.brimit.com/blog?platforms=Sales%20and%20marketing%20automation)
