# How Telegram Desktop Configures Automated Builds in Its CI/CD Pipeline: A Complete Guide to GitHub Actions

> Discover how Telegram Desktop configures automated builds in its CI/CD pipeline using GitHub Actions. Learn about platform workflows, caching strategies and artifact uploads.

- Repository: [Telegram Desktop/tdesktop](https://github.com/telegramdesktop/tdesktop)
- Tags: how-to-guide
- Published: 2026-04-05

---

**Telegram Desktop uses GitHub Actions with platform-specific workflow files ([`win.yml`](https://github.com/telegramdesktop/tdesktop/blob/main/win.yml), [`linux.yml`](https://github.com/telegramdesktop/tdesktop/blob/main/linux.yml), [`mac.yml`](https://github.com/telegramdesktop/tdesktop/blob/main/mac.yml)) to automate builds for Windows, Linux, and macOS, leveraging matrix strategies, aggressive caching of third-party dependencies, and artifact upload steps for every push and pull request.**

The `telegramdesktop/tdesktop` repository maintains a sophisticated continuous integration system that produces debug builds across all major desktop platforms automatically. Understanding how these automated builds are configured in the CI/CD pipeline reveals a pattern of matrix-driven workflows, path-optimized triggers, and reusable caching layers that minimize build times while ensuring code quality.

## Windows CI/CD Pipeline Configuration

The Windows automation is defined in [`.github/workflows/win.yml`](https://github.com/telegramdesktop/tdesktop/blob/main/.github/workflows/win.yml) and represents the most complex build matrix in the system.

### Build Matrix and Triggers

The workflow triggers on every `push` and `pull_request` event, deliberately ignoring documentation, Markdown files, and legal text to prevent unnecessary builds. The matrix strategy varies three critical dimensions:

- **Architecture**: `x64_x86`, `x64`, or `arm64`
- **Qt Version**: Empty string (default) or `qt6`
- **CMake Generator**: Default or `"Ninja Multi-Config"`

Optional compile-time `defines` allow testing of conditional compilation flags without modifying source code.

### Environment Setup and Caching

The workflow executes on `windows-latest` or `windows-11-arm` runners with Visual Studio 2022. Key preparation steps include:

1. Creating a shared `TBuild` folder and symlinking it into the workspace
2. Detecting the Windows SDK version from [`docs/building-win.md`](https://github.com/telegramdesktop/tdesktop/blob/main/docs/building-win.md)
3. Installing MSVC command-prompt tools via **ilammy/msvc-dev-cmd**
4. Restoring cached **ThirdParty**, **Libraries**, and **Qt** directories using `actions/cache`

The cache key incorporates a SHA256 hash of [`prepare.py`](https://github.com/telegramdesktop/tdesktop/blob/main/prepare.py) combined with the OS and architecture, ensuring that dependency script changes invalidate the cache appropriately.

### Build Execution and Artifact Generation

The actual compilation follows a strict sequence:

```yaml

# Excerpt from win.yml logic

- name: Prepare dependencies
  run: Telegram\build\prepare\win.bat skip-release silent ${{ matrix.qt }}

- name: Configure CMake
  run: configure.bat ${{ matrix.generator }} ${{ matrix.arch }} ${{ matrix.qt }} ...

- name: Build
  run: cmake --build ..\out --config Debug --parallel

```

After `cmake` completes, the workflow collects `Telegram.exe` and `Updater.exe`, placing them in an `artifact/` directory for upload via `actions/upload-artifact`.

## Linux Automated Build Configuration

Linux builds use [`.github/workflows/linux.yml`](https://github.com/telegramdesktop/tdesktop/blob/main/.github/workflows/linux.yml) with a containerized approach to ensure reproducible Rocky Linux 8 environments.

### Docker-Based Build Environment

Unlike Windows, the Linux pipeline builds and runs a custom Docker image defined in `Telegram/build/docker/centos_env`. The workflow:

1. Installs Poetry to generate the Dockerfile dynamically
2. Caches Docker build layers using `.buildx-cache`
3. Builds the image via `docker/build-push-action`
4. Mounts the repository into the container with `CONFIG=Debug`

Inside the container, the entrypoint script [`Telegram/build/docker/centos_env/build.sh`](https://github.com/telegramdesktop/tdesktop/blob/main/Telegram/build/docker/centos_env/build.sh) executes the compilation with debug-oriented flags.

### CMake Configuration and Compilation

The Linux build script passes explicit CMake configuration flags optimized for CI debugging:

```bash
cmake -D CMAKE_CONFIGURATION_TYPES=Debug \
      -D CMAKE_C_FLAGS_DEBUG="-O0 -fuse-ld=lld" \
      -D DESKTOP_APP_DISABLE_X11_INTEGRATION=${{ matrix.defines }} \
      ...

```

After verifying the binary at `out/Debug/Telegram`, the workflow packages both `Telegram` and `Updater` into the `artifact/` folder for upload.

## macOS CI Pipeline Setup

The macOS configuration in [`.github/workflows/mac.yml`](https://github.com/telegramdesktop/tdesktop/blob/main/.github/workflows/mac.yml) targets `macos-latest` runners with a simpler matrix (currently only varying empty `defines`).

The preparation phase installs toolchain dependencies via Homebrew:

```yaml
- name: Install dependencies
  run: brew install automake meson nasm ninja pkg-config

```

After disabling Spotlight to prevent indexing overhead, the workflow caches the **Libraries** and **ThirdParty** directories before running `Telegram/build/prepare/mac.sh skip-release silent`. The build then executes through [`./configure.sh`](https://github.com/telegramdesktop/tdesktop/blob/main/./configure.sh) with debug-specific flags like `-D CMAKE_COMPILE_WARNING_AS_ERROR=ON`, followed by `cmake --build ../out --config Debug --parallel`.

The resulting `Telegram.app` bundle and `Updater` binary are moved to `artifact/` and uploaded.

## Common CI/CD Architecture Patterns

Across all three platforms, the Telegram Desktop automated builds share architectural principles that optimize for speed and reliability.

### Path-Based Trigger Optimization

All workflows implement identical path-ignore rules that skip builds when only documentation, Markdown, or workflow files themselves change. This prevents wasting runner minutes on non-code modifications.

### Matrix-Driven Variations

The **Windows** pipeline exploits the most complex matrix to test multiple architectures and Qt versions simultaneously. **Linux** uses the matrix primarily for compile-time feature flags like `DESKTOP_APP_DISABLE_X11_INTEGRATION`. **macOS** maintains an extensible single-configuration setup ready for future expansion.

### Preparation Script Abstraction

Each platform invokes a thin wrapper—`win.bat`, [`mac.sh`](https://github.com/telegramdesktop/tdesktop/blob/main/mac.sh), or the Docker [`build.sh`](https://github.com/telegramdesktop/tdesktop/blob/main/build.sh)—that delegates to the central [`Telegram/build/prepare/prepare.py`](https://github.com/telegramdesktop/tdesktop/blob/main/Telegram/build/prepare/prepare.py) script. This abstraction allows the CI to handle platform-specific path conventions while maintaining a single source of truth for dependency resolution.

### Artifact Publication Strategy

Every workflow concludes by uploading debug binaries via `actions/upload-artifact`, making them instantly accessible from the GitHub Actions run page without requiring repository write permissions.

## Accessing and Using Build Artifacts

Developers can interact with the CI system programmatically for testing or release preparation.

### Triggering Manual Builds

To initiate a build from a feature branch without pushing code, use the `workflow_dispatch` event or repository dispatch:

```yaml
name: Manual Build Trigger
on:
  workflow_dispatch:
    inputs:
      platform:
        description: 'Target platform'
        required: true
        default: 'windows'
        type: choice
        options:
          - windows
          - linux
          - macos

```

Since the existing workflows react to `push` events, triggering a dummy commit or using `peter-evans/repository-dispatch@v2` routes the request to the appropriate platform workflow.

### Downloading Artifacts via CLI

Retrieve the latest Windows build artifacts using the GitHub CLI:

```bash

# List recent runs and extract the database ID

RUN_ID=$(gh run list --workflow win.yml -L 1 --json databaseId -q '.[0].databaseId')

# Download the Qt6 build artifact

gh run download $RUN_ID --name "Telegram x64 qt6"

```

### Inspecting Cache Keys

To debug cache hits or misses, reference the `CACHE_KEY` environment variable generated early in each workflow:

```yaml
- name: Display cache key
  run: echo "Current cache key: ${{ env.CACHE_KEY }}"

```

This key combines the `sha256sum` of [`prepare.py`](https://github.com/telegramdesktop/tdesktop/blob/main/prepare.py) with platform identifiers, ensuring that dependency updates automatically invalidate stale caches.

## Summary

- **Telegram Desktop** automates builds across Windows, Linux, and macOS using dedicated workflow files in `.github/workflows/` (win.yml, linux.yml, mac.yml).
- The **Windows** pipeline employs a complex build matrix testing x64, x86, ARM64, and multiple Qt versions using Visual Studio 2022.
- **Linux** builds run inside a Docker container built from `Telegram/build/docker/centos_env` to ensure Rocky Linux 8 compatibility.
- **macOS** builds rely on Homebrew toolchains and Xcode-free compilation with aggressive caching of third-party libraries.
- All platforms use **path-based triggers** to skip builds on documentation changes, **matrix strategies** for multi-configuration testing, and **actions/upload-artifact** to publish debug binaries.
- Centralized preparation logic in [`Telegram/build/prepare/prepare.py`](https://github.com/telegramdesktop/tdesktop/blob/main/Telegram/build/prepare/prepare.py) ensures consistent dependency management across different operating systems.

## Frequently Asked Questions

### How does Telegram Desktop prevent unnecessary CI builds on documentation changes?

The workflow files in [`.github/workflows/win.yml`](https://github.com/telegramdesktop/tdesktop/blob/main/.github/workflows/win.yml), [`linux.yml`](https://github.com/telegramdesktop/tdesktop/blob/main/linux.yml), and [`mac.yml`](https://github.com/telegramdesktop/tdesktop/blob/main/mac.yml) all specify `paths-ignore` filters that exclude Markdown files, documentation directories, license text, and the workflow files themselves from the `push` and `pull_request` triggers. This ensures that editing README files or legal notices does not consume runner resources.

### What caching strategy does the Windows CI use to speed up builds?

The Windows workflow caches the **ThirdParty**, **Libraries**, and **Qt** directories using `actions/cache`. The cache key incorporates a SHA256 hash of [`Telegram/build/prepare/prepare.py`](https://github.com/telegramdesktop/tdesktop/blob/main/Telegram/build/prepare/prepare.py) combined with the OS type and architecture. If the preparation script changes—indicating new dependencies—the cache automatically invalidates and rebuilds.

### How can I download the debug binaries produced by the automated builds?

Each workflow uploads artifacts via `actions/upload-artifact` at the end of the build process. You can download these directly from the GitHub Actions run page in the browser, or use the GitHub CLI with commands like `gh run download <run-id> --name "Telegram x64 qt6"` to fetch specific matrix variants programmatically.

### Why does the Linux pipeline use Docker while Windows and macOS use native runners?

The Linux workflow targets a specific Rocky Linux 8 environment to maintain binary compatibility with older glibc versions, ensuring the resulting executables run on a wide range of Linux distributions. The Docker image defined in `Telegram/build/docker/centos_env` provides this controlled environment, whereas Windows and macOS builds target specific OS versions natively available through GitHub-hosted runners.