> This page is for SDKs, version Current (default).
> For other versions, use one of these documentation indexes:
> - Current (default): https://buildwithfern.com/learn/sdks/current/llms.txt
> - Legacy: https://buildwithfern.com/learn/sdks/legacy/llms.txt

> For clean Markdown content of this page, append .md to this URL. For the complete documentation index, see https://buildwithfern.com/learn/llms.txt.

# Publishing to NuGet

> Learn how to publish your Fern-generated C#/.NET SDK to NuGet using OIDC or API key authentication, with step-by-step configuration and GitHub Actions setup.

> **Enterprise feature**
>
> This feature is available only for the [Enterprise plan](https://buildwithfern.com/pricing). To get started, reach out to [support@buildwithfern.com](mailto:support@buildwithfern.com).

Publish your public-facing Fern C#/.NET SDK to the [NuGet registry](https://www.nuget.org/). After following the steps on this page,
you'll have a versioned package published on NuGet. To distribute the SDK
internally instead, generate to the local file system (optionally
[self-hosted](/learn/sdks/deep-dives/self-hosted)) and build a `.nupkg` with
[`fern generate --package`](/learn/cli-api-reference/cli-reference/sdk-commands#package).

> **Already publishing to NuGet?**
>
> If you're using API key authentication, consider switching to OIDC (trusted publishing). See [Migrating from API key to OIDC publishing](#migrating-from-api-key-to-oidc-publishing) for the steps.

![Versioned package published on NuGet](/learn/_fern-files/_img/c5a21d0bd777a975fd6a18cc8fcd151b81d2ea386ab89d47ab52a7d75047ce35.webp)

> **Info**
>
> This page assumes that you have:
>
> * An initialized `fern` folder, a GitHub repository for your C#/.NET SDK, and a C#/.NET target in `sdk-config.yml`. See [Generating an SDK (C#/.NET)](/learn/sdks/generators/csharp/quickstart).

Before proceeding, verify the prerequisites are actually in place:

1. **Source repo with `fern/` folder**: The user should be working in their source repo, not the SDK repo. Confirm `sdk-config.yml` exists and has a C#/.NET target.
2. **C#/.NET target**: If they skipped the [C# quickstart](/learn/sdks/generators/csharp/quickstart), they need to add a `language: csharp` entry to `targets` first.

Default to OIDC authentication unless the user has a specific reason to use API key auth. OIDC is more secure and avoids managing NuGet API keys.

## Configure SDK package settings

Update the C#/.NET target in `sdk-config.yml` to configure the package name and client name for NuGet publishing. Your `sdk-config.yml` [should live in your source repository](/learn/sdks/overview/project-structure) (or on your local machine), not the repository that contains your C#/.NET SDK code.

#### Add a unique package name

Your package name must be unique in the NuGet registry, otherwise publishing your SDK will fail.

**`sdk-config.yml`**

```yaml {3-4} title="sdk-config.yml"
targets:
  - language: csharp
    package:
      packageName: your-package-name
```

#### Configure the client name

The `generation.naming.clientName` option controls the name of the generated client class.

**`sdk-config.yml`**

```yaml {5-7} title="sdk-config.yml"
targets:
  - language: csharp
    package:
      packageName: your-package-name
    generation:
      naming:
        clientName: YourClientName # must be PascalCase
```

The description, authors, keywords, and repository links on your package's nuget.org listing come from the target's [`package`](/learn/sdks/reference/sdk-config#package) metadata.

## Configure GitHub publishing

Fern can automatically publish your SDK to NuGet via GitHub Actions. Set `output.delivery` to `github`, configure your repository and publishing mode, and set `output.publish.registry` to `nuget`:

Optionally set the mode to control how Fern handles SDK publishing:

* `mode: release` (default): Fern generates code, commits to the default branch (or the `branch` you specify), and tags a release automatically
* `mode: pull-request` (recommended):  Fern generates code and creates a PR for you to review before release
* `mode: push`: Fern generates code and pushes to a branch you specify for you to review before release

You can also configure other settings, like the reviewers or license. Refer to the [`output.github` reference](/learn/sdks/reference/sdk-config#github) for more information.

**`sdk-config.yml`**

```yaml title="sdk-config.yml" {8-15}
targets:
  - language: csharp
    package:
      packageName: your-package-name
    generation:
      naming:
        clientName: YourClientName
    output:
      delivery: github
      github:
        repository: your-org/company-csharp
        mode: push  # or "pull-request"
        branch: your-branch-name  # Required for mode: push
      publish:
        registry: nuget
```

## Configure authentication

Choose how you want to authenticate with NuGet when publishing. **OpenID Connect (OIDC) authentication is recommended** because it removes the need to manage long-lived API keys.

#### OIDC authentication (Recommended)

OIDC-based publishing (also known as "trusted publishing") is the most secure way to publish. With OIDC, you don't need to manage API keys — NuGet trusts your GitHub repository to publish directly via short-lived tokens scoped to your workflow.

#### Configure OIDC

`sdk-config.yml` supports trusted publishing only for npm. To add `api-key: OIDC` with `generators.yml`, see [Legacy NuGet publishing](/learn/sdks/legacy/generators/csharp/publishing#configure-authentication).

#### Generate your SDK

Generate your SDK to create the GitHub Actions workflow with OIDC configuration:

```bash
fern generate --target csharp
```

This creates a `.github/workflows/ci.yml` file configured to use OIDC for NuGet publishing. The generated workflow includes:

* A `publish` job with `permissions: { contents: read, id-token: write }`
* The [`NuGet/login@v1`](https://github.com/NuGet/login) action, which exchanges a GitHub OIDC token for a short-lived NuGet API key (\~1 hour)
* `dotnet nuget push` using the temporary API key from the login step

#### Authorize your repository on nuget.org

Configure trusted publishing on nuget.org to allow your GitHub repository to publish:

1. Go to [nuget.org](https://www.nuget.org/) and click your user avatar
2. Select **Trusted Publishing** > **Create policy**
3. Fill in:
   * **Repository Owner**: Your GitHub organization or username
   * **Repository**: Your C# SDK repository name
   * **Workflow File**: `ci.yml` (filename only, without the `.github/workflows/` prefix)
4. Choose the policy owner (organization profile or personal account). The policy applies to all packages owned by that profile.

#### Set the \`NUGET_USER\` GitHub Actions secret

The generated workflow requires a `NUGET_USER` secret containing your nuget.org profile name (not your email).

1. Open your SDK repository on GitHub and go to **Settings**
2. Navigate to **Secrets and variables** > **Actions**
3. Click **New repository secret**
4. Name it `NUGET_USER` and enter your nuget.org profile name
5. Click **Add secret**

> **Info**
>
> For private repositories, the trust policy starts as **temporarily active for 7 days**. It becomes permanent after the first successful login binds the repository and owner IDs. Run the publish workflow within that 7-day window.

#### Troubleshooting

**"Unable to authenticate" error**

Common causes:

* Workflow filename doesn't match exactly (must be `ci.yml`)
* Trusted publisher configuration on nuget.org doesn't match your repository settings
* A stale `NUGET_API_KEY` secret is interfering with OIDC authentication

**Solution:** Double-check your trusted publisher configuration on nuget.org matches your repository name and workflow filename exactly. Remove any old `NUGET_API_KEY` secret from your repository.

**Private repository limitations**

For private repositories, the trust policy is temporarily active for 7 days. It becomes permanent after the first successful login. Run the publish workflow within that window.

#### API key authentication (Legacy)

#### Generate a NuGet API key

1. Log into [NuGet](https://nuget.org/) or create a new account
2. Click on your profile picture
3. Select **API Keys**, then **Create**
4. Name your key
5. Select **Push > Push new packages and package versions** as the **Select Scopes** type
6. Enter `*` under **Select Packages > Glob Pattern**

   > **Replacing an existing NuGet package**
   >
   > If you are overriding an existing package, select the relevant
   > package instead of entering `*`.
7. Click **Create**

![Creating a new API key](/learn/_fern-files/_img/7d0063cf1d598f3a137208bed660abcabcc990d8936e2d10cca376803c7214df.webp)

> **Warning**
>
> Save your new key — it won't be displayed after you leave the page.

#### Add API key

`sdk-config.yml` doesn't have a NuGet credential field yet. To add `api-key: ${NUGET_API_KEY}` with `generators.yml`, see [Legacy NuGet publishing](/learn/sdks/legacy/generators/csharp/publishing#configure-authentication).

#### Add \`NUGET_API_KEY\` as a GitHub Actions secret

1. Open your repository on GitHub and go to **Settings**
2. Navigate to **Secrets and variables** > **Actions**
3. Click **New repository secret**
4. Name it `NUGET_API_KEY` and paste your NuGet API key
5. Click **Add secret**

![NUGET\_API\_KEY secret](/learn/_fern-files/_img/fe114ac818cc31b427a032317ea8eeeff188210ced36200aaf3b970284b783a9.webp)

## Publish your SDK

Your SDK will automatically be published to NuGet when you create a GitHub release with a version tag:

1. Create a GitHub release with a version tag (for example, `v1.0.0`)
2. The CI workflow will run automatically and publish to NuGet
3. View your package on nuget.org to confirm the version

#### Alternative: Manual workflow dispatch

If you prefer to trigger publishes manually from your source repository, set up a release workflow via [GitHub Actions](https://docs.github.com/en/actions).

#### Add secret for your Fern API key

1. Open your source repository on GitHub and go to **Settings**
2. Navigate to **Secrets and variables** > **Actions**
3. Select **New repository secret**
4. Name your secret `FERN_TOKEN`
5. Add your Fern API key. If you don't already have one, generate one by
   running `fern token`. By default, the API key is generated for the
   organization listed in `fern.config.json`.
6. Click **Add secret**

If you use API key authentication, also add a `NUGET_API_KEY` secret with your NuGet API key.

#### Set up a new workflow

Create a CI workflow that you can manually trigger from the GitHub UI. Navigate to **Actions** > **New workflow** > **Set up workflow yourself**:

**`.github/workflows/publish.yml`**

```yaml title=".github/workflows/publish.yml" maxLines=0
name: Publish C#/.NET SDK

on:
  workflow_dispatch:
    inputs:
      version:
        description: "The version of the C#/.NET SDK that you would like to release"
        required: true
        type: string

jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repo
        uses: actions/checkout@v4

      - name: Install Fern CLI
        run: npm install -g fern-api

      - name: Release C#/.NET SDK
        env:
          FERN_TOKEN: ${{ secrets.FERN_TOKEN }}
          NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }} # Only needed for API key authentication
        run: |
          fern generate --target csharp --version ${{ inputs.version }} --log-level debug
```

#### Regenerate and release your SDK

Navigate to the **Actions** tab, select the workflow, specify a version number, and click **Run workflow**. This regenerates your SDK.

![Running C# publish workflow](/learn/_fern-files/_img/519254f94e2afce5b51212349518eb55548d713cc84d77f5aebd1bcc2d688495.webp)

The rest of the release process depends on your chosen mode:

* **Release mode (default):** If you didn't specify a `mode` or set `mode: release`, no further action is required. Fern automatically tags the new release with your specified version number and initiates the publishing workflow in your SDK repository.

* **Pull request or push mode:** If you set `mode: pull-request` or `mode: push`, Fern creates a pull request or pushes to a branch respectively. Review and merge the PR (`pull-request`) or branch (`push`), then [tag a new release](https://docs.github.com/en/repositories/releasing-projects-on-github/managing-releases-in-a-repository) to initiate the publishing workflow in your SDK repository.

Once the workflow completes, view your new release by logging into NuGet and navigating to **Manage Packages**.

#### Alternative: Release via CLI and environment variables

#### Set NuGet environment variable

If you use API key authentication, set the `NUGET_API_KEY` environment variable on your local machine:

```bash
export NUGET_API_KEY=your-actual-nuget-api-key
```

#### Regenerate and release your SDK

Regenerate your SDK, specifying the version:

```bash
fern generate --target csharp --version <version>
```

The rest of the release process depends on your chosen mode:

* **Release mode (default):** If you didn't specify a `mode` or set `mode: release`, no further action is required. Fern automatically tags the new release with your specified version number and initiates the publishing workflow in your SDK repository.

* **Pull request or push mode:** If you set `mode: pull-request` or `mode: push`, Fern creates a pull request or pushes to a branch respectively. Review and merge the PR (`pull-request`) or branch (`push`), then [tag a new release](https://docs.github.com/en/repositories/releasing-projects-on-github/managing-releases-in-a-repository) to initiate the publishing workflow in your SDK repository.

Once the workflow completes, view your new release by logging into NuGet and navigating to **Manage Packages**.

---

## Migrating from API key to OIDC publishing

Migrating to OIDC publishing uses `generators.yml`. See [Migrating from API key to OIDC publishing](/learn/sdks/legacy/generators/csharp/publishing#migrating-from-api-key-to-oidc-publishing) in the Legacy docs.