diff --git a/fern/products/sdks/overview/typescript/publishing-to-npm.mdx b/fern/products/sdks/overview/typescript/publishing-to-npm.mdx
index 1c24d9742..0ec156a52 100644
--- a/fern/products/sdks/overview/typescript/publishing-to-npm.mdx
+++ b/fern/products/sdks/overview/typescript/publishing-to-npm.mdx
@@ -3,12 +3,16 @@ title: Publishing to npm
description: How to publish the Fern TypeScript SDK to npm.
---
-Publish your public-facing Fern TypeScript SDK to the [npm
+Publish your public-facing Fern TypeScript SDK to the [npmjs
registry](https://www.npmjs.com/). After following the steps on this page,
you'll have a versioned package published on npm.
+
+If you're currently using token-based authentication, npmjs is deprecating long-lived tokens in early 2025. See [Migrating from token-based to OpenID Connect (OIDC) publishing](#migrating-from-token-based-to-oidc-publishing) to upgrade to the more secure OIDC authentication.
+
+
-
+
@@ -29,10 +33,10 @@ You'll need to update your `generators.yml` file to configure the package name,
- In the `group` for your TypeScript SDK, change the output location from `local-file-system` (the default) to `npm` to indicate that Fern should publish your package directly to the npm registry:
+ In the `group` for your TypeScript SDK, change the output location from `local-file-system` (the default) to `npm` to indicate that Fern should publish your package directly to the npmjs registry:
```yaml {6-7} title="generators.yml"
- groups:
+ groups:
ts-sdk: # Group name for your TypeScript SDK
generators:
- name: fernapi/fern-typescript-sdk
@@ -45,10 +49,10 @@ You'll need to update your `generators.yml` file to configure the package name,
- Your package name must be unique in the npm repository, otherwise publishing your SDK to npm will fail.
+ Your package name must be unique in the npmjs registry, otherwise publishing your SDK will fail.
```yaml {8} title="generators.yml"
- groups:
+ groups:
ts-sdk:
generators:
- name: fernapi/fern-typescript-sdk
@@ -62,10 +66,10 @@ You'll need to update your `generators.yml` file to configure the package name,
- The `namespaceExport` 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';`).
+ The `namespaceExport` 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 {9-10} title="generators.yml"
- groups:
+ groups:
ts-sdk:
generators:
- name: fernapi/fern-typescript-sdk
@@ -81,259 +85,457 @@ You'll need to update your `generators.yml` file to configure the package name,
-## Generate an npm token
+## Configure GitHub publishing
+
+Fern can automatically publish your SDK to npmjs via GitHub Actions. Configure your GitHub repository and publishing mode:
+
+
+
+```yaml title="generators.yml" {11-14}
+groups:
+ ts-sdk:
+ generators:
+ - name: fernapi/fern-typescript-sdk
+ version:
+ output:
+ location: npm
+ package-name: your-package-name
+ config:
+ namespaceExport: YourClientName
+ github:
+ repository: your-org/your-repository
+ mode: push # or "pull-request"
+ branch: your-branch-name # Required for mode: push
+```
+
+## Configure authentication
+
+Choose how you want to authenticate with npmjs when publishing.
+
+
+**Starting in early 2025**, npmjs.org is deprecating long-lived authentication tokens for publishing from CI/CD workflows. **OpenID Connect (OIDC) authentication is strongly recommended** for security.
+
+
+
+
+
+OIDC-based publishing (also known as "trusted publishing") is the most secure way to publish. With OIDC, you don't need to manage authentication tokens - npmjs trusts your GitHub repository to publish directly.
+
+
+- Fern TypeScript SDK generator version `3.12.0` or later
+- Fern CLI version `0.94.0` or later (only required for local generation with `--local`)
+
+
-
+ Add `token: OIDC` to the `output` section:
- Log into [npm](https://www.npmjs.com/) or create a new account.
+ ```yaml title="generators.yml" {9}
+ groups:
+ ts-sdk:
+ generators:
+ - name: fernapi/fern-typescript-sdk
+ version: # Must be 3.12.0 or later
+ output:
+ location: npm
+ package-name: your-package-name
+ token: OIDC
+ config:
+ namespaceExport: YourClientName
+ github:
+ repository: your-org/your-repository
+ mode: push
+ branch: your-branch-name
+ ```
-
+
+
+ Generate your SDK to create the GitHub Actions workflow with OIDC configuration:
+
+ ```bash
+ fern generate --group ts-sdk
+ ```
+
+ This creates a `.github/workflows/ci.yml` file that's configured to use OIDC for npmjs publishing. Alternatively, you can push your `generators.yml` changes and let the Fern GitHub Action generate the workflow for you.
- 1. Click on your profile picture.
- 1. Select **Edit Profile**.
- 1. Select **Access Tokens**.
+ This creates a `.github/workflows/ci.yml` file that's configured to use OIDC for npm publishing.
-
+
- Click on **Generate New Token**, then choose the appropriate token type.
-
- For more information on access tokens and which type to choose, see npm's [About access tokens](https://docs.npmjs.com/about-access-tokens) documentation.
+ Configure trusted publishing on npmjs.com to allow your GitHub repository to publish:
-
-
+ 1. Navigate to your package settings on npmjs.com
+ 1. Find the **Trusted Publisher** section and click **Add trusted publisher**
+ 1. Select **GitHub Actions** as your provider
+ 1. Fill in:
+ - **Organization or user**: Your GitHub username or organization
+ - **Repository**: Your TypeScript SDK repository name (e.g., `your-org/your-repository`)
+ - **Workflow filename**: `ci.yml`
+ - **Environment name**: Leave blank
- 1. Select **Classic Token**
- 1. Name your token and select **Automation** as the token type.
- 1. Click **Generate Token**.
+ For more details, see npm's [trusted publishing documentation](https://docs.npmjs.com/trusted-publishers).
- Save your new token – it won't be displayed after you leave the page.
+
+
-
-
-
+
-
-
- 1. Select **Granular Access Token**.
- 1. Name your token.
- 1. Set an expiration.
- 1. Configure your token's access to packages and scopes.
- 1. Configure your token's access to organizations. In order to fill this out, you must have at least one organization already configured in npm. See [Creating an organization](https://docs.npmjs.com/creating-an-organization) for more information.
- 1. Optionally fill out additional permissions according to your organization's requirements.
- 1. Click **Generate Token**.
+**"Unable to authenticate" error**
- Save your new token – it won't be displayed after you leave the page.
+Common causes:
+- Workflow filename doesn't match exactly (must be `ci.yml`)
+- Trusted publisher configuration on npmjs.com doesn't match your repository settings
+- Using self-hosted runners (not currently supported by npmjs.org)
-
-
-
+**Solution:** Double-check your trusted publisher configuration on npmjs.com matches your repository name and workflow filename exactly.
-
-
-
-
+**Private repository limitations**
-
+Provenance attestations aren't generated for packages published from private repositories, even when using trusted publishing. This is a [known limitation](https://github.blog/changelog/2023-07-25-publishing-with-npm-provenance-from-private-source-repositories-is-no-longer-supported/).
+
+
+
+
+
+
-## Configure npm publication
+
+**This method is being deprecated by npmjs.org in early 2025.** Long-lived authentication tokens can be exposed in logs, compromised, and are difficult to manage and rotate. [OIDC-based authentication is strongly recommended instead](#migrating-from-token-based-to-oidc-publishing).
+
-
+
- Add the path to the GitHub repository containing your TypeScript SDK:
+1. Log into [npmjs.com](https://www.npmjs.com/)
+1. Click on your profile picture and select **Edit Profile**
+1. Select **Access Tokens**
+1. Click **Generate New Token** and choose either **Classic Token** (select "Automation" type) or **Granular Access Token**
+1. Save your token securely - it won't be displayed again
- ```yaml {11-12} title="generators.yml"
- groups:
- ts-sdk:
- generators:
- - name: fernapi/fern-typescript-sdk
- version:
- output:
- location: npm
- package-name: your-package-name
- config:
- namespaceExport: YourClientName
- github:
- repository: your-org/company-typescript
- ```
+For more information on access tokens, see npm's [About access tokens](https://docs.npmjs.com/about-access-tokens) documentation.
-
-Add `token: ${NPM_TOKEN}` to `generators.yml` to tell Fern to use the `NPM_TOKEN` environment variable for authentication when publishing to the npm registry.
+
+
+Add `token: ${NPM_TOKEN}` to the `output` section:
```yaml title="generators.yml" {9}
-groups:
+groups:
ts-sdk:
generators:
- name: fernapi/fern-typescript-sdk
version:
output:
location: npm
- package-name: name-of-your-package
+ package-name: your-package-name
token: ${NPM_TOKEN}
config:
namespaceExport: YourClientName
- github:
+ github:
repository: your-org/your-repository
+ mode: push
+ branch: your-branch-name
```
+
-
-
+
-```yaml title="generators.yml" {14}
-groups:
- ts-sdk:
- generators:
- - name: fernapi/fern-typescript-sdk
- version:
- output:
- location: npm
- package-name: name-of-your-package
- token: ${NPM_TOKEN}
- config:
- namespaceExport: YourClientName
- github:
- repository: your-org/your-repository
- mode: push
- branch: your-branch-name # Required for mode: push
-```
+1. Open your repository on GitHub and go to **Settings**
+1. Navigate to **Secrets and variables** > **Actions**
+1. Click **New repository secret**
+1. Name it `NPM_TOKEN` and paste your npm token
+1. Click **Add secret**
+
+
+
+
## Publish your SDK
-Decide how you want to publish your SDK to npm. You can use GitHub workflows for automated releases or publish directly via the CLI.
+Your SDK will automatically be published to npmjs when you create a GitHub release with a version tag:
+
+1. Create a GitHub release with a version tag (for example, `v1.0.0`)
+1. The CI workflow will run automatically and publish to npm
+1. View your package on npmjs.com to confirm the new version
+
+
+
+If you prefer to trigger publishes manually, create a `.github/workflows/publish.yml` file:
+
+```yaml title=".github/workflows/publish.yml"
+name: Publish TypeScript SDK
+
+on:
+ workflow_dispatch:
+ inputs:
+ version:
+ description: "Version to publish (e.g., 1.0.0)"
+ required: true
+ type: string
+
+jobs:
+ publish:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout repo
+ uses: actions/checkout@v4
+
+ - name: Install Fern
+ run: npm install -g fern-api
+
+ - name: Generate and publish SDK
+ env:
+ FERN_TOKEN: ${{ secrets.FERN_TOKEN }}
+ run: fern generate --group ts-sdk --version ${{ inputs.version }} --log-level debug
+```
+
+Add your `FERN_TOKEN` as a repository secret (run `fern token` to generate one), then trigger the workflow from the **Actions** tab.
+
+
+
+---
+
+## Migrating from token-based to OIDC publishing
+
+If you're currently using token-based authentication and need to migrate to OIDC, follow these steps:
+
+### Why migrate to OIDC
+
+npmjs is implementing trusted publishing to remove security risks associated with long-lived tokens, which can be:
+
+- Exposed in logs or configuration files
+- Compromised and used persistently until manually revoked
+- Difficult to manage and rotate
+
+OIDC-based publishing uses short-lived, cryptographically signed tokens that are specific to your workflow and can't be extracted or reused.
+
+### Prerequisites
+
+Before migrating, ensure you have:
+
+- A package published to [npmjs.org](https://npmjs.org)
+- A GitHub repository with GitHub Actions configured
+- Access to your package settings on [npmjs.com](https://npmjs.com)
+- Fern CLI version `0.94.0` or later (for local generation)
+
+### Choose your migration path
+
+Select the approach that fits your situation:
+
-
+This is the easiest path if you can upgrade to version 3.12.0 or later of the TypeScript SDK generator.
-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.
+**When to use this path:**
+- You're able to upgrade to Fern TypeScript SDK generator version 3.12.0 or later
+- You haven't `.fernignore`'d your CI workflow file
-
+
+
+ Follow npm's ["Add a trusted publisher on npmjs.com"](https://docs.npmjs.com/trusted-publishers#step-1-add-a-trusted-publisher-on-npmjscom) instructions:
+
+ 1. Navigate to your package settings on [npmjs.com](https://npmjs.com)
+ 1. Find the **Trusted Publisher** section and click **Add trusted publisher**
+ 1. Select **GitHub Actions** as your provider
+ 1. Configure:
+ - **Organization or user**: Your GitHub username or organization
+ - **Repository**: Your TypeScript SDK repository name
+ - **Workflow filename**: `ci.yml` (the default Fern workflow file)
+ - **Environment name**: Leave blank (unless you use GitHub environments)
+
+
+
+
+
+ Change the `output.token` field from `${NPM_TOKEN}` to `OIDC` and ensure you're using version `3.12.0` or later:
+
+ ```yaml title="generators.yml"
+ groups:
+ ts-sdk:
+ generators:
+ - name: fernapi/fern-typescript-sdk
+ version: # Must be 3.12.0 or later
+ output:
+ location: npm
+ package-name: your-package-name
+ token: OIDC # Changed from ${NPM_TOKEN}
+ config:
+ namespaceExport: YourClientName
+ github:
+ repository: your-org/your-repository
+ ```
+
+
+
+
+
+ Regenerate your SDK with the updated CI configuration. You can do this either:
+
+ **Locally:**
- Open your source repository in GitHub. Click on the **Settings** tab. Then, under the **Security** section, open **Secrets and variables** > **Actions**.
+ ```bash
+ fern generate --group ts-sdk
+ ```
+
+ **Or via GitHub Actions:**
-
-
-
+ If you use the Fern GitHub Action to generate your SDK, simply push your updated `generators.yml` file and let the workflow regenerate the SDK for you.
- You can also use the url `https://github.com//settings/secrets/actions`.
+ This will update your `.github/workflows/ci.yml` file with the required OIDC permissions.
-
- 1. Select **New repository secret**.
- 1. Name your secret `NPM_TOKEN`.
- 1. Add the corresponding token you generated above.
- 1. Click **Add secret**.
+
-
-
-
+ After verifying the migration works, remove the `NPM_TOKEN` secret from your GitHub repository settings to prevent accidental use.
-
+
+
+
+
+
+
+Use this path if you can't upgrade the generator or have customized your CI workflow.
+
+**When to use this path:**
+- You can't upgrade due to breaking changes or bugs
+- You've customized your CI workflow and added it to `.fernignore`
+- Path 1 didn't update your workflow file
- 1. Select **New repository secret**.
- 1. Name your secret `FERN_TOKEN`.
- 1. 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`.
- 1. Click **Add secret**.
+
+
+
+ Follow the same instructions as Path 1 to add your repository as a trusted publisher on npmjs.com.
-
-
- 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 TypeScript SDK
-
- on:
- workflow_dispatch:
- inputs:
- version:
- description: "The version of the TypeScript 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 TypeScript SDK
- env:
- FERN_TOKEN: ${{ secrets.FERN_TOKEN }}
- NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
- run: |
- fern generate --group ts-sdk --version ${{ inputs.version }} --log-level debug
+
+
+
+ Open your `.github/workflows/ci.yml` file and make these changes to the `publish` job:
+
+ ```yaml title=".github/workflows/ci.yml"
+ publish:
+ needs: [ compile, test ]
+ if: github.event_name == 'push' && contains(github.ref, 'refs/tags/')
+ runs-on: ubuntu-latest
+ permissions:
+ id-token: write # ADD THIS: Required for OIDC
+ steps:
+ - name: Checkout repo
+ uses: actions/checkout@v4
+
+ - name: Set up node
+ uses: actions/setup-node@v4
+
+ # ADD THIS: Ensure npm 11.5.1 or later is installed for OIDC support
+ - name: Update npm
+ run: npm install -g npm@latest
+
+ - name: Install pnpm
+ uses: pnpm/action-setup@v4
+
+ - name: Install dependencies
+ run: pnpm install
+
+ - name: Build
+ run: pnpm build
+
+ # MODIFY THIS: Remove npm config set and env block
+ - name: Publish to npm
+ run: |
+ if [[ ${GITHUB_REF} == *alpha* ]]; then
+ npm publish --access public --tag alpha
+ elif [[ ${GITHUB_REF} == *beta* ]]; then
+ npm publish --access public --tag beta
+ else
+ npm publish --access public
+ fi
+ # Previously had:
+ # run: |
+ # npm config set //registry.npmjs.org/:_authToken ${NPM_TOKEN}
+ # if [[ ${GITHUB_REF} == *alpha* ]]; then
+ # npm publish --access public --tag alpha
+ # elif [[ ${GITHUB_REF} == *beta* ]]; then
+ # npm publish --access public --tag beta
+ # else
+ # npm publish --access public
+ # fi
+ # env:
+ # NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
```
-
- You can alternatively configure your workflow to execute `on: [push]`. See Vapi's [npm publishing GitHub Action](https://github.com/VapiAI/server-sdk-typescript/blob/main/.github/workflows/ci.yml) for an example.
-
-
-
+ **Key changes:**
+ - Add `permissions` block with `id-token: write` to the publish job
+ - Add step to update npm to version 11.5.1 or later
+ - Remove the `npm config set` line from the publish step
+ - Remove the `env` block with `NPM_TOKEN` from the publish step
- Navigate to the **Actions** tab, select the workflow you just created, specify a version number, and click **Run workflow**. This regenerates your SDK.
+
+
+
-
-
-
+ If you haven't already, add your CI workflow to `.fernignore` to prevent future generator updates from overwriting your manual changes:
-
+ ```text title=".fernignore"
+ .github/workflows/ci.yml
+ ```
- Once the workflow completes, you can view your new release by logging into npm and navigating to **Packages**.
-
+
+
+ After verifying the migration works, remove the `NPM_TOKEN` secret from your GitHub repository settings.
+
+
+
-
-
+### Verify your migration
-
+After completing either migration path:
-Set the `NPM_TOKEN` environment variable on your local machine:
+1. **Trigger a workflow run** by creating a GitHub release with an alpha tag (for example, `v1.0.0-alpha`)
+2. **Check the workflow logs** to verify the publish step succeeds
+3. **Verify provenance** by visiting your package on [npmjs.com](https://npmjs.com) - you should see a provenance badge
-```bash
-export NPM_TOKEN=your-actual-npm-token
-```
+### Migration troubleshooting
-
-
+
+
-Regenerate your SDK, specifying the version:
+**Common causes:**
+- Workflow filename doesn't match exactly (must be `ci.yml` with the `.yml` extension)
+- Missing `id-token: write` permission in workflow
+- npm CLI version is older than 11.5.1
+- Using self-hosted runners (not currently supported)
-```bash
-fern generate --group ts-sdk --version
-```
+**Solution:** Double-check your trusted publisher configuration on npmjs.com matches your actual workflow file name and verify all requirements are met.
-
+
-Once the workflow completes, you can view your new release by logging into npm and navigating to **Packages**.
+
-
+If your workflow continues using the old token-based authentication:
+
+- Verify you've removed the `npm config set` line and the `env: NPM_TOKEN` block from the publish step
+- Check that npm CLI version 11.5.1+ is installed (add the update npm step)
+- Ensure you're using generator version 3.12.0 or later (if using Path 1)
+- When using `--local` generation, you need to use Fern CLI version 0.94.0 or later
-