---
title: "MSBuild Setup"
description: "Configure MSBuild properties in your .NET project to automatically use the Sentry CLI."
url: https://docs.sentry.io/platforms/dotnet/guides/winforms/configuration/msbuild/
---

# MSBuild Setup | Sentry for Windows Forms

The [Sentry CLI](https://docs.sentry.io/cli.md) has many useful features that can improve your Sentry experience. For .NET, you can use it to upload [debug information files](https://docs.sentry.io/cli/dif.md), such as .NET `PDB` symbol files. This allows Sentry to show a more complete stack trace, including file names and line numbers. You can also use it to upload *source code*, which enables Sentry to display [source context](https://docs.sentry.io/platforms/dotnet/guides/winforms/data-management/debug-files/source-context.md) when viewing stack traces.

While you can always run `sentry-cli` from the command line manually, we've made it easier by including it in the `Sentry` NuGet package, and providing properties to enable it from your build.

## [Authentication](https://docs.sentry.io/platforms/dotnet/guides/winforms/configuration/msbuild.md#authentication)

For this feature to work, you must authenticate to Sentry on the machine that is performing your release builds.

##### Important

The Sentry auth token (or legacy API key) should always be treated as secret. Be careful not to commit authentication information to source control, or use it in any way that it would be written to log files.

Any of the authentication methods accepted by the Sentry CLI can be used. See [Configuration and Authentication](https://docs.sentry.io/cli/configuration.md). However, we generally recommend the following:

* If building your releases on a developer workstation, [install the Sentry CLI](https://docs.sentry.io/cli/installation.md) and then call `sentry-cli login` to use the [automatic configuration](https://docs.sentry.io/cli/configuration.md#to-use-the-automatic-option) option. This will help you create an auth token and save it to the `~/.sentryclirc` file on the workstation.

* If building from a CI/CD server, use the secrets feature of your CI/CD platform to set the `SENTRY_AUTH_TOKEN` environment variable.

  For example, if using GitHub Actions, first set an [encrypted secret](https://docs.github.com/actions/security-guides/encrypted-secrets) and then pass the secret via the `SENTRY_AUTH_TOKEN` environment variable to the step performing your build action.

  ```yaml
  steps:
    - name: Build
      run: dotnet build -c Release
      env:
        SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
  ```

  You do not need to separately install Sentry CLI on your build server, as it is already provided by the Sentry NuGet package.

* If building inside a **Docker container**, use a [BuildKit secret](https://docs.docker.com/build/building/secrets/) to pass the auth token securely. See [Building with Docker](https://docs.sentry.io/platforms/dotnet/guides/winforms/configuration/msbuild.md#building-with-docker) below for a complete example.

## [Configuration](https://docs.sentry.io/platforms/dotnet/guides/winforms/configuration/msbuild.md#configuration)

In addition to authentication, you must configure your Sentry organization and project slugs. You may also want to configure other [optional properties](https://docs.sentry.io/platforms/dotnet/guides/winforms/configuration/msbuild.md#optional-msbuild-properties).

The slugs can be found in various places from the Sentry UI, such as in the URL after selecting a project. For example, the organization slug is `example-org` and the project slug is `example-project` in the following URLs:

* `https://example-org.sentry.io/projects/example-project/?project=1234567`
* `https://sentry.io/organizations/example-org/projects/example-project/?project=1234567`

If you are self-hosting Sentry (rather than using sentry.io), then you will also need to provide the URL to your Sentry server.

##### Tip

Any of the [Sentry CLI configuration values](https://docs.sentry.io/cli/configuration.md#configuration-values) can be set via environment variables or in configuration files, such as shown in the above authentication steps.

However, other than authentication, you should consider setting configuration values via the MSBuild properties described below, such that they are part of your code that is committed to source control. This allows them to be consistent across environments, and also allows the settings to differ per each project in your solution, if desired.

If *both* MSBuild properties and environment variables are provided, the MSBuild properties will take precedence.

### [Setting MSBuild Properties](https://docs.sentry.io/platforms/dotnet/guides/winforms/configuration/msbuild.md#setting-msbuild-properties)

Sentry's MSBuild properties can be set in any MSBuild project file, such as those that are created by Visual Studio or the `dotnet` CLI (`YourProject.csproj`, `YourProject.vbproj`, `Directory.Build.props`, etc.). We recommend using a dedicated property group, so that you can control when these features are used.

In the following example, `Condition="'$(Configuration)' == 'Release'"` ensures that these features are enabled only for release builds. This is the usual recommendation, because sending data to Sentry during debug builds can slow down your development workflow.

Alternatively, you could control this using any MSBuild property or environment variable you like. For example, if you only want these features enabled in a GitHub Actions CI workflow, you could use `Condition="'$(GITHUB_ACTIONS)' == 'true'"`.

```xml
<!-- We recommend only using these features for release builds. -->
<PropertyGroup Condition="'$(Configuration)' == 'Release'">

  <!-- Configure Sentry org and project -->
  <SentryOrg><your-org-slug></SentryOrg>
  <SentryProject><your-project-slug></SentryProject>

  <!--
    Each of the below features are opt-in.
    Enable the features you wish to use.
  -->

  <!-- Automatically creates a release when building your application. -->
  <SentryCreateRelease>true</SentryCreateRelease>

  <!-- Automatically associates commits with the release. -->
  <SentrySetCommits>true</SentrySetCommits>

  <!-- Optionally provide explicit flags to the set-commits command -->
  <SentrySetCommitOptions>--local</SentrySetCommitOptions>

  <!-- Sends symbols to Sentry, enabling symbolication of stack traces. -->
  <SentryUploadSymbols>true</SentryUploadSymbols>

  <!-- Sends sources to Sentry, enabling display of source context. -->
  <SentryUploadSources>true</SentryUploadSources>

  <!-- If you are targeting Android, sends proguard mapping file to Sentry. -->
  <SentryUploadAndroidProGuardMapping
  >true</SentryUploadAndroidProGuardMapping>

</PropertyGroup>
```

Alternatively, they could be passed as parameters when building your project. For example:

```shell
dotnet build YourProject.csproj -c Release -p:SentryOrg=<your-org-slug> -p:SentryProject=<your-project-slug> -p:SentryUploadSymbols=true -p:SentryUploadSources=true
```

##### Tip

You may have properties that are the same across multiple projects in your solution. Consider placing these properties in a [`Directory.Build.props`](https://learn.microsoft.com/visualstudio/msbuild/customize-your-build) file, so that they are shared with all projects automatically.

### [Required MSBuild Properties](https://docs.sentry.io/platforms/dotnet/guides/winforms/configuration/msbuild.md#required-msbuild-properties)

The following MSBuild properties will pass required information to the Sentry CLI:

### [SentryOrg](https://docs.sentry.io/platforms/dotnet/guides/winforms/configuration/msbuild.md#SentryOrg)

| Type | `string` |
| ---- | -------- |

The organization slug for your Sentry account.

### [SentryProject](https://docs.sentry.io/platforms/dotnet/guides/winforms/configuration/msbuild.md#SentryProject)

| Type | `string` |
| ---- | -------- |

The project slug for the specific Sentry project you are using.

### [SentryUrl](https://docs.sentry.io/platforms/dotnet/guides/winforms/configuration/msbuild.md#SentryUrl)

| Type | `string` |
| ---- | -------- |

The URL to your Sentry server. Required only if self-hosting Sentry. (Do not use with sentry.io.)

### [Optional MSBuild Properties](https://docs.sentry.io/platforms/dotnet/guides/winforms/configuration/msbuild.md#optional-msbuild-properties)

There are a few additional properties available to control the Sentry CLI:

### [SentryCreateRelease](https://docs.sentry.io/platforms/dotnet/guides/winforms/configuration/msbuild.md#SentryCreateRelease)

| Type    | `bool`  |
| ------- | ------- |
| Default | `false` |

Enable to automatically create release when building your application. Defaults to `false` (disabled).

Sentry will try to determine the release version automatically by checking the following sources in order:

1. The `SENTRY_RELEASE` environment variable, if set
2. The `AssemblyInformationalVersionAttribute`, if defined
3. The version of the entry assembly for the project
4. The version suggested by running `sentry-cli releases propose-version`

### [SentrySetCommits](https://docs.sentry.io/platforms/dotnet/guides/winforms/configuration/msbuild.md#SentrySetCommits)

| Type | `bool` |
| ---- | ------ |

Enable `SentrySetCommits` to automatically [associate commits with the release](https://docs.sentry.io/cli/releases.md#commit-integration).

### [SentrySetCommitOptions](https://docs.sentry.io/platforms/dotnet/guides/winforms/configuration/msbuild.md#SentrySetCommitOptions)

| Type | `string` |
| ---- | -------- |

By default, when `SentrySetCommits` is enabled, the SDK will set commits with the `--auto` flag. The optional `SentrySetCommitOptions` property allows you to override this to provide whatever flags you want to the `set-commits` CLI command.

### [SentryUploadSymbols](https://docs.sentry.io/platforms/dotnet/guides/winforms/configuration/msbuild.md#SentryUploadSymbols)

| Type    | `bool`  |
| ------- | ------- |
| Default | `false` |

Controls uploading symbols to Sentry during the build. Defaults to `false` (disabled).

Set this property to `true` to opt-in to sending symbols to Sentry as [debug information files](https://docs.sentry.io/platforms/dotnet/guides/winforms/data-management/debug-files.md), which are used to perform symbolication of stack traces. This will allow you to view file names and line numbers within a stack trace, instead of just a function name.

### [SentryUploadSources](https://docs.sentry.io/platforms/dotnet/guides/winforms/configuration/msbuild.md#SentryUploadSources)

| Type    | `bool`  |
| ------- | ------- |
| Default | `false` |

Controls whether source code files are uploaded to Sentry during the build. Defaults to `false` (disabled).

Set this property to `true` to opt-in to sending source code to Sentry. This enables the display of [source context](https://docs.sentry.io/platforms/dotnet/guides/winforms/data-management/debug-files/source-context.md) when viewing stack traces.

If you are already embedding source code in your symbol files using [`EmbedAllSources`](https://github.com/dotnet/sourcelink/blob/main/docs/README.md#embedallsources), you do not need to upload them to Sentry separately. In other words, use *either* `SentryUploadSources` or `EmbedAllSources`, not both.

### [UseSentryCLI](https://docs.sentry.io/platforms/dotnet/guides/winforms/configuration/msbuild.md#UseSentryCLI)

| Type    | `bool` |
| ------- | ------ |
| Default | `true` |

Controls whether the Sentry CLI is enabled in your build. Defaults to `true` if any of the individual features are enabled. Set to `false` to disable the Sentry CLI completely, ignoring the settings of each feature.

##### Important

There are two more properties, `SentryAuthToken` and `SentryApiKey`, that are available for authentication. However we recommend that they are used only for simple testing, and not for production. If you decide to use them, be very careful that their values are not committed to source control or appear in build logs. A more secure approach is to set authentication via environment variable or `~/.sentryclirc` file,

## [Building with Docker](https://docs.sentry.io/platforms/dotnet/guides/winforms/configuration/msbuild.md#building-with-docker)

When building inside a Docker container, there are two things to handle: passing the auth token securely, and avoiding errors in multi-stage builds.

### [Passing the Auth Token](https://docs.sentry.io/platforms/dotnet/guides/winforms/configuration/msbuild.md#passing-the-auth-token)

Use Docker BuildKit's `--secret` flag to pass the auth token at build time. Unlike `ARG`/`ENV`, BuildKit secrets are never written to any image layer and do not appear in `docker history`.

Pass the secret when building the image:

```bash
docker build --secret id=sentry_auth_token,env=SENTRY_AUTH_TOKEN .
```

In your Dockerfile, add a [syntax directive](https://docs.docker.com/reference/dockerfile/#syntax) at the top, then mount the secret for the `RUN` instruction that performs the build:

```dockerfile
# syntax=docker/dockerfile:1
...
RUN --mount=type=secret,id=sentry_auth_token,env=SENTRY_AUTH_TOKEN \
    dotnet build "MyWebApp.csproj" --no-restore -c Release
```

The `env=` option (available since Dockerfile syntax v1.10) exposes the secret as the `SENTRY_AUTH_TOKEN` environment variable for the duration of that `RUN` instruction only — exactly what the Sentry CLI needs — without persisting it to a layer. The `# syntax=` directive ensures Docker uses a frontend that supports `env=`, regardless of the Docker Engine version.

BuildKit is enabled by default in Docker 23.0 and later. For older versions, set `DOCKER_BUILDKIT=1` in your environment before running `docker build`.

### [Multi-Stage Dockerfiles](https://docs.sentry.io/platforms/dotnet/guides/winforms/configuration/msbuild.md#multi-stage-dockerfiles)

If your Dockerfile has separate stages for `dotnet build` and `dotnet publish` (a common pattern for ASP.NET Core apps), Sentry CLI only needs to run during the **build** stage, where the auth token is mounted.

By default, `dotnet publish` runs its own implicit build. That would invoke Sentry CLI again — and because the auth token is deliberately scoped to the build stage's `RUN` (so it never reaches the publish stage or the final image), the second run would fail. Pass `--no-build --no-restore` so `dotnet publish` reuses the build stage's output instead of recompiling, plus `-p:UseSentryCLI=false` as an extra safeguard:

```dockerfile
RUN dotnet publish "MyWebApp.csproj" -c Release -o /app/publish --no-build --no-restore -p:UseAppHost=false -p:UseSentryCLI=false
```

### [Complete Example](https://docs.sentry.io/platforms/dotnet/guides/winforms/configuration/msbuild.md#complete-example)

The following is a complete multi-stage Dockerfile for an ASP.NET Core app. It assumes `<SentryOrg>`, `<SentryProject>`, `<SentryUploadSymbols>`, and `<SentryUploadSources>` are configured in your `.csproj` or `Directory.Build.props`.

```dockerfile
# syntax=docker/dockerfile:1
# Build: docker build --secret id=sentry_auth_token,env=SENTRY_AUTH_TOKEN .
FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS base
WORKDIR /app
EXPOSE 8080

FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
WORKDIR /src
COPY ["MyWebApp.csproj", "./"]
RUN dotnet restore "MyWebApp.csproj"
COPY . .

# The secret is available only for this RUN instruction and is never written to a layer.
# Sentry CLI runs here and uploads debug symbols as part of the build.
RUN --mount=type=secret,id=sentry_auth_token,env=SENTRY_AUTH_TOKEN \
    dotnet build "MyWebApp.csproj" --no-restore -c Release

# Reuse the build output; --no-build avoids recompiling, which would re-run Sentry CLI without the auth token.
FROM build AS publish
RUN dotnet publish "MyWebApp.csproj" -c Release -o /app/publish --no-build --no-restore -p:UseAppHost=false -p:UseSentryCLI=false

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "MyWebApp.dll"]
```
