# Publishing to PyPI

> How to publish the Fern Python SDK to PyPI.

Publish your public-facing Fern Python SDK to the [PyPI
registry](https://pypi.org/). After following the steps on this page,
you'll have a versioned package published on PyPI.

<Frame>
  <img src="https://files.buildwithfern.com/fern.docs.buildwithfern.com/learn/4fc87f38377f7454855545fa0af2644d685cbf5e4e9e9ec04d17d23384499f68/products/sdks/overview/python/assets/pypi-package.png" alt="Versioned package published on PyPI" />
</Frame>

<Info>
  This page assumes that you have:

  * An initialized `fern` folder. See [Set up the `fern`
    folder](/sdks/overview/quickstart).
  * A GitHub repository for your Python SDK. See [Project structure](/sdks/overview/project-structure).
  * A Python generator group in `generators.yml`. See [Python
    Quickstart](quickstart#add-the-sdk-generator).
</Info>

## Configure SDK package settings

You'll need to update your `generators.yml` file to configure the package name, output location, and client naming for PyPi publishing. Your `generators.yml` [should live in your source repository](/sdks/overview/project-structure) (or on your local machine), not the repository that contains your Python SDK code.

<Steps>
  <Step title="Configure `output` location">
    In the `group` for your Python SDK, change the output location in from `local-file-system` (the default) to `pypi` to indicate that Fern should publish your package directly to the PyPi registry:

    ```yaml title="generators.yml" {6-7}
    groups: 
      python-sdk:
        generators:
          - name: fernapi/fern-python-sdk
            version: 4.50.1
            output:
              location: pypi

    ```
  </Step>

  <Step title="Add a unique package name">
    Your package name must be unique in the PyPI repository, otherwise publishing your SDK to PyPI will fail.

    ```yaml title="generators.yml" {8}
    groups: 
      python-sdk:
        generators:
          - name: fernapi/fern-python-sdk
            version: 4.50.1
            output:
              location: pypi
              package-name: your-package-name
    ```
  </Step>

  <Step title="Configure `client-class-name`">
    The `client-class-name` option controls the name of the generated client. This is the name customers use to import your SDK (`import { your-client-name } from 'your-package-name';`).

    ```yaml title="generators.yml" {9-10}
    groups: 
      python-sdk:
        generators:
          - name: fernapi/fern-python-sdk
            version: 4.50.1
            output:
              location: pypi
              package-name: your-package-name
            config:
              client_class_name: YourClientName # must be PascalCase
    ```
  </Step>

  <Step title="Add PyPI metadata (optional)">
    You can add publishing metadata to your PyPI package to improve discoverability and provide additional information to users. This metadata appears on your package's PyPI page and includes `keywords` for PyPI search and discovery, `documentation-link` for your package documentation, and `homepage-link` for your project homepage.

    You can additionally add general metadata for the SDK (description, contact email, author, license, etc.) at [the individual SDK level](/learn/sdks/reference/generators-yml#metadata-2) or [globally for all SDKs](/learn/sdks/reference/generators-yml#metadata).

    ```yaml title="generators.yml" {9, 13}
    groups: 
      python-sdk:
        generators:
          - name: fernapi/fern-python-sdk
            version: 4.50.1
            output:
              location: pypi
              package-name: your-package-name
              metadata: # Publishing metadata
                keywords: ["api", "sdk", "client"]
                documentation-link: "https://docs.yourcompany.com"
                homepage-link: "https://yourcompany.com"
            metadata: # General SDK metadata
              license: MIT
            config:
              client_class_name: YourClientName
    ```
  </Step>
</Steps>

## Generate a PyPi token

<Steps>
  <Step title="Log into PyPi">
    Log into [PyPi](https://pypi.org/) or create a new account.
  </Step>

  <Step title="Navigate to Account settings">
    1. Click on your profile picture.
    2. Select **Account settings**.
    3. Scroll down to **API Tokens**.
  </Step>

  <Step title="Add New Token">
    1. Click on **Add API Token**
    2. Name your token and set the scope to the relevant projects.
    3. Click **Create token**

    <Frame>
      <img src="https://files.buildwithfern.com/fern.docs.buildwithfern.com/learn/e4cd601fc8bc0d93bb4673b9fcfe38547d2e85a62b857779dc8584039de005c5/products/sdks/overview/python/assets/new-api-token.png" alt="Creating a New API Token" />
    </Frame>

    <Warning>
      Save your new token –  it won’t be displayed after you leave the page.
    </Warning>
  </Step>
</Steps>

## Configure PyPi publication

<Steps>
  <Step title="Add repository location">
    Add the path to your GitHub repository to `generators.yml`:

    ```yaml title="generators.yml" {11-12}
    groups: 
      python-sdk:
        generators:
          - name: fernapi/fern-python-sdk
            version: 4.50.1
            output:
              location: pypi
              package-name: your-package-name
            config:
              client_class_name: YourClientName
            github: 
              repository: your-org/company-python
    ```
  </Step>

  <Step title="Configure PyPi authentication token">
    Add `token: ${PYPI_TOKEN}` to `generators.yml`.

    ```yaml {9} title="generators.yml"
    groups: 
      python-sdk:
        generators:
          - name: fernapi/fern-python-sdk
            version: 4.50.1
            output:
              location: pypi
              package-name: your-package-name
              token: ${PYPI_TOKEN}
            config:
              client_class_name: YourClientName
            github: 
              repository: your-org/company-python
    ```
  </Step>

  <Step title="Choose your publishing mode">
    Optionally set the mode to control how Fern handles SDK publishing:

    * `mode: release` (default): Fern generates code, commits to main, and tags a release automatically
    * `mode: pull-request`:  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 [full `github` (`generators.yml`) reference](/sdks/reference/generators-yml#github) for more information.

    ```yaml title="generators.yml" {14}
    groups: 
      python-sdk:
    	generators:
    	  - name: fernapi/fern-python-sdk
    		version: 4.50.1
    		output:
    		  location: npm
    		  package-name: name-of-your-package
    		  token: ${PYPI_TOKEN}
    		config:
    		  namespaceExport: YourClientName
    		github: 
    		  repository: your-org/your-repository
    		  mode: push
    		  branch: your-branch-name # Required for mode: push
    ```
  </Step>
</Steps>

## Publish your SDK

Decide how you want to publish your SDK to PyPi. You can use GitHub workflows for automated releases or publish directly via the CLI.

<AccordionGroup>
  <Accordion title="Release via a GitHub workflow (recommended)">
    Set up a release workflow via [GitHub Actions](https://docs.github.com/en/actions/get-started/quickstart) so you can trigger new SDK releases directly from your source repository.

    <Steps>
      <Step title="Set up authentication">
        Open your Fern repository in GitHub. Click on the **Settings** tab in your repository. Then, under the **Security** section, open **Secrets and variables** > **Actions**.

        <Frame>
          <img src="https://files.buildwithfern.com/fern.docs.buildwithfern.com/learn/9fc4fb8ff04bfa66390a409bfee35e79643af42118ad2586339407854185b53f/products/sdks/overview/python/assets/github-secret.png" alt="Adding GitHub Repository Secret" />
        </Frame>

        You can also use the url `https://github.com/<your-repo>/settings/secrets/actions`.
      </Step>

      <Step title="Add secret for your PyPi Token">
        1. Select **New repository secret**.
        2. Name your secret `PYPI_TOKEN`.
        3. Add the corresponding token you generated above.
        4. Click **Add secret**.

        <Frame>
          <img src="https://files.buildwithfern.com/fern.docs.buildwithfern.com/learn/8d303ec569da7ccbcc655f65bd22cb9e2b930d0e72343f56424b4a5435607aec/products/sdks/overview/python/assets/pypi-token-secret.png" alt="PYPI_TOKEN secret" />
        </Frame>
      </Step>

      <Step title="Add secret for your Fern Token">
        1. Select **New repository secret**.
        2. Name your secret `FERN_TOKEN`.
        3. Add your Fern token. If you don't already have one, generate one by
           running `fern token`. By default, the `fern_token` is generated for the
           organization listed in `fern.config.json`.
        4. Click **Add secret**.
      </Step>

      <Step title="Set up a new workflow">
        Set up a CI workflow that you can manually trigger from the GitHub UI. In your repository, navigate to **Actions**. Select **New workflow**, then **Set up workflow yourself**. Add a workflow that's similar to this:

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

        on:
          workflow_dispatch:
            inputs:
              version:
                description: "The version of the Python 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 Python SDK
                env:
                  FERN_TOKEN: ${{ secrets.FERN_TOKEN }}
                  PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }}
                run: |
                  fern generate --group python-sdk --version ${{ inputs.version }} --log-level debug
        ```
      </Step>

      <Step title="Regenerate and release your SDK">
        Navigate to the **Actions** tab, select the workflow you just created, specify a version number, and click **Run workflow**. This regenerates your SDK.

        <Frame>
          <img src="https://files.buildwithfern.com/fern.docs.buildwithfern.com/learn/0e57015fd638ff28f1abda12e7bb1d94f97b793d041512051dbbb45124a08566/products/sdks/overview/python/assets/python-sdk-release-action.png" alt="Running Python publish workflow" />
        </Frame>

        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, you can view your new release by logging into PyPi and navigating to **Your projects**.
      </Step>
    </Steps>
  </Accordion>

  <Accordion title="Release via CLI and environment variables">
    <Steps>
      <Step title="Set PyPI environment variable">
        Set the `PYPI_TOKEN` environment variable on your local machine:

        ```bash
        export PYPI_TOKEN=your-actual-pypi-token
        ```
      </Step>

      <Step title="Regenerate and release your SDK">
        Regenerate your SDK, specifying the version:

        ```bash
        fern generate --group python-sdk --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, you can view your new release by logging into PyPi and navigating to **Your projects**.
      </Step>
    </Steps>
  </Accordion>
</AccordionGroup>