XM Cloud and Netlify - Deploy with GitHub Actions

Jared Arnofsky,XM CloudNetlify

Summary

Recently, we had a requirement to deploy code from a private repository in GitHub to both Sitecore XM Cloud and Netlify. There are native ways to accomplish this, but the client wanted full control from one location to manage everything. This meant that GitHub actions and leveraging the proper CLI commands for each platform was a good fit.

In previous blog posts I have talked about deploying to XM Cloud (opens in a new tab) and deploying to Netlify (opens in a new tab) using their own CLI tools. While a couple things have changed the general concept and idea is the same. I'm not going to deep dive into these topics individually again, but please feel free to check them out if you haven't already.

In this blog post, we will focus on how to leverage GitHub actions to deploy our code base to XM Cloud and our headless application to Netlify. For this example, we are using the Sitecore XM Cloud Starter Repository (opens in a new tab) as a base, which comes with a Sitecore JSS SXA Headless Next.js application.

The Solution

Netlify leverages a netlify.toml file with it's CLI. This is a file-based configuration that specifies how Netlify finds, builds and deploys your application. You can read up more on it here (opens in a new tab).

We need a parent level netlify.toml as we are deploying to XM cloud at our parent directory and then deploying only the headless application to Netlify (src/app).

At the base netlify.toml we need to specify where our headless application is in our repository. For example src/app.

[build]
base = "/src/app"

In the source of your headless application, src/app, add a netlify.toml specifying your build command for the headless application. The command will be specific to your use case. We are using pnpm, but npm and any other commands will work here as well.

Note that we need to specify both the publish and functions parameters. Additionally, since we are using a next.js site we set the proper Netlify Next.js plugin.

[build]
command = "pnpm run build"
publish = ".next"
functions = "netlify/functions"

[[plugins]]
package = "@netlify/plugin-nextjs"

Once the toml files are set up we can work on building our GitHub Action. In the base of your repo in .github/workflows folder create and new file called deploy.yml. To read more about GitHub Actions check out the documentation here (opens in a new tab).

We will walk through the steps of a simple example, this can be fine tuned and optimized for Production use.

The first step is defining the Action and when you want it to run:

Definition

In our example we are specifying to only run on commit to the develop and main branches. We are setting the concurrency so that the job does not run more than once at a time. Additionally, we leverage GitHub environment variables to control what values are set for each branch so we don't need to write the action multiple times. Please check out the documentation here (opens in a new tab).

The next step is to install all of our dependencies for the XM Cloud deploy:

XM Cloud Dependencies

In our example we make sure we specify using .NET core, we then restore and install our dotnet tools. Lastly, we had to add the .net global tools to PATH so we can leverage it.

Next, we authenticate and deploy to XM Cloud:

XM Cloud Deploy

If you are using the recommended Sitecore XM cloud FED First approach, then you are most likely deploying your items using SCS and the CLI to non DEV environments:

XM Cloud SCS

Now that the XM Cloud deployment is complete, we can deploy to Netlify. The first step is to install all the necessary dependencies:

Netlify Dependencies

In our example we set up Node so that we can use npm and ultimately pnpm. Deno is installed as it is a requirement of Netlify.

Last, we deploy to Netlify

Netlify Deploy

Final Script

Combined, the deploy.yml GitHub action script looks like this:

name: Deploy to XM Cloud and Netlify

on:
  push:
    branches:
      - develop
      - main

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}

jobs:
  deploy:
    runs-on: ubuntu-latest
    environment: ${{ (github.ref_name == 'main' && 'prod') || (github.ref_name == 'develop' && 'dev') }}

    steps:

      - name: Checkout code
        uses: actions/checkout@v4

      ## XM Cloud deployment

      - name: Setup .NET core
        uses: actions/setup-dotnet@v4
        with:
          dotnet-version: '6.0.406'

      - name: Restore .net tools
        run: dotnet tool restore --add-source https://sitecore.myget.org/F/sc-packages/api/v3/index.json

      - name: Install Sitecore CLI globally
        run: dotnet tool install --global sitecore.cli --version 5.2.113

      - name: Add .net global tools to PATH
        run: echo "$HOME/.dotnet/tools" >> $GITHUB_PATH

      - name: Authenticate with Sitecore Cloud
        run: |
          dotnet sitecore cloud login --client-credentials --client-id ${{ secrets.XM_CLOUD_CLIENT_ID }} --client-secret ${{ secrets.XM_CLOUD_CLIENT_SECRET }}

        run: |
          dotnet sitecore cloud deployment create --working-dir . --upload --environment-id ${{ secrets.XM_CLOUD_ENVIRONMENT_ID }}
    
      - name: Connect to XM Cloud an Deploy SCS Items
        if: github.ref_name == 'qa' || github.ref_name == 'prod'
        run: |
          dotnet sitecore cloud environment connect --environment-id ${{ secrets.XM_CLOUD_ENVIRONMENT_ID }} --allow-write true
          dotnet sitecore serialization push -n ${{ secrets.XM_CLOUD_ENVIRONMENT_NAME }} --exclude RenderingHost

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 22

      - name: Install Deno
        run: npm install -g deno
        working-directory: apps/website

      - name: Install pnpm
        run: npm install -g pnpm
        working-directory: apps/website

      - name: Install pnpm
        run: pnpm install
        working-directory: apps/website

      # Netlify deployment

      - name: Netlify deploy
        run: |
          npx netlify deploy --build --site ${{ secrets.NETLIFY_SITE_ID }} --auth ${{ secrets.NETLIFY_AUTH_TOKEN }} --prod
        working-directory: apps/website

Conclusion

Netlify and Sitecore give us flexible CLI tools to leverage in our CI/CD pipelines. GitHub actions are a great way to control and deploy all your XM Cloud artifacts from one central location. In our example one commit can deploy to XM Cloud and Netlify with ease.