Publish your SDKs
Once you are satisfied with the structure and naming conventions of your SDK, you can distribute them to end users by publishing them
to package registries (for example, npm
, PyPI
, and maven
). After a one-time setup, future Stainless SDKs flow from our private preview repository to your GitHub organization where they're picked up by the package registries.
The Stainless managed release flow handles versioning and changelogs expected in quality SDKs. You can even automate this process so subsequent changes to your OpenAPI spec trigger new SDK releases.
Identify or create your GitHub repositories
When getting started, we generate SDKs into private preview repositories under stainless-sdks
. But your users expect them to be found in repos within your GitHub organization.
If you do not have a repository yet, you need to create one.
Be sure to select the correct organization as the owner and set a name that meaningfully identifies your SDK—for example, <my-brand>-python
is a common choice for Python SDKs.
The repository can be public or private.
You need one GitHub repo for each language SDK (one for Node, one for Python, and so on).
Install the Stainless GitHub App
The Stainless GitHub App does the work of pushing preview SDKs to your repos. To install it:
- Navigate to the correct project in the Stainless dashboard.
- For one of your target languages, click Edit > Install GitHub App. (It does not matter from which language you trigger this process.)
- Follow the installation flow. When prompted, select which repositories the Stainless GitHub App can access.
- Once repositories have been selected and permissions have been reviewed, click Install & Authorize.
By default All repositories is selected, but we recommend you only select the repositories you plan to use for Stainless SDKs.
Connect package registries
Package registries make your packages readily available to your users. Once configured, Stainless automatically updates package registries on releases, but you have to complete a one-time setup and give Stainless permissions to update your packages on your behalf.
Node/TypeScript: npm
Get an Automation API token
- Log in or sign up at npm.
- Click on your profile picture on the top right to access a dropdown and then navigate to Access Tokens > Generate New Token.
- Choose a token version:
- Granular Access Token, recommended if you’re publishing the SDK under a scope (for example,
@<your-company-name>/sdk
) - Classic Token, required if not publishing under a scope
- Granular Access Token, recommended if you’re publishing the SDK under a scope (for example,
- If creating a Classic Token, ensure you have selected Automation as the token type. Apart from that, the token settings you choose are up to you.
Add the API token to your Node GitHub repository
- Navigate to the actions secrets for your repository at Secrets and variables > Actions > New repository secret, the URL should look like
https://github.com/<org>/<repo>/settings/secrets/actions/new
. - Add a new secret named
NPM_TOKEN
with your API token from the Get an Automation API token step.
Choose a package name and update the Stainless dashboard
-
You have to choose an available name in the registry. Suggested names are:
<your-company-name>
@<your-company-name>/sdk
(This requires you have the right npm organization.)
You can check if the name is available.
-
Update the Stainless dashboard with your package name. The SDK generation process restarts and pushes to NPM once it is done.
Deno: jsr
Create a package
- Go to JSR > Publish a package.
- Select an appropriate scope and package name, click Create.
(Option 1) Publish with GitHub OIDC
-
Navigate to <Package> > Settings > GitHub Repository.
-
Link your production GitHub repository to the package you created in the previous step.
-
Navigate to your <Scope> > Settings > GitHub Actions security.
-
Select Do not restrict publishing. This will let our bot publish even though it is not a member of your scope.
-
Modify your stainless config:
node:
package_name: <package-name>
publish:
npm: true
jsr:
package_name: @<scope>/<package>
(Option 2) Use access token to publish
-
Navigate to Account > Tokens > Personal access tokens > Create new token.
-
Navigate through wizard to get your token:
- Publish packages
- A development machine
- Create a token
- Create a token for the package name.
-
Modify your stainless config:
node:
package_name: <package-name>
publish:
npm: true
jsr:
package_name: @<scope>/<package>
use_access_token: true -
Navigate to the actions secrets for your repository at Secrets and variables > Actions > New repository secret, the URL should look like
https://github.com/<org>/<repo>/settings/secrets/actions/new
. -
Add a new secret named
JSR_TOKEN
with your API token.
Python: PyPI
Get an API token
- Log in or sign up at PyPI.
- Navigate to your account settings.
- Scroll down to the API tokens section and click Add API Token. You may have to verify your email address and set up 2FA if you haven't done so already.
Add the API token to your Python GitHub repository
- Navigate to the actions secrets for your repository at Secrets and variables > Actions > New repository secret, the URL should look like
https://github.com/<org>/<repo>/settings/secrets/actions/new
. - Add a new secret named
PYPI_TOKEN
with your API token from the Get an API token step.
Choose a package name and update the Stainless dashboard
-
You have to choose an available name in the registry. Suggested names are:
<your-company-name>
<your-company-name>-client
You can check whether the name is available by testing the link at
https://pypi.org/project/<your-package-name>
. If it is available, PyPI should say that the package is now available. -
Update the Stainless dashboard with your package name. The SDK generation process restarts and pushes to PyPI once it is done.
Ruby: RubyGems
Get an API token
- Log in or sign up at RubyGems.
- Navigate to your settings tab and click on "API keys" link towards bottom of page.
- Create a new API key with "push rubygems" privileges, make sure MFA is disabled.
Add the API token to your Ruby GitHub repository
- Navigate to the actions secrets for your repository at Secrets and variables > Actions > New repository secret, the URL should look like
https://github.com/<org>/<repo>/settings/secrets/actions/new
. - Add a new secret named
GEM_HOST_API_KEY
with your API token from the Get an API token step.
Choose a package name and update the Stainless dashboard
-
You have to choose an available name in the registry. Suggested names are:
<your-company-name>
<your-company-name>-client
You can check whether the name is available by testing the link at
https://rubygems.org/gems/<your-package-name>
. If it is available, RubyGems should say that the package is now available. -
Update the Stainless dashboard with your package name. The SDK generation process restarts and pushes to RubyGems once it is done.
Java & Kotlin: Sonatype Maven Central
We publish JVM packages to Sonatype. Sonatype has both a legacy (OSSRH) publishing flow and a new Central Portal publishing flow.
If you do not already publish to OSSRH, you will most likely have to use the new Central Portal publishing flow. If you are already publishing to OSSRH, you can continue to do so.
Setting up Sonatype can be an involved process. We recommend you go through this process after getting your SDKs into a satisfactory state.
Modify Stainless configuration (Central Portal only)
For backwards compatibility, currently the default sonatype_platform
is ossrh
. If you are using the Central Portal, you need to update the Stainless configuration.
In the Stainless dashboard, under targets.{java,kotlin}.publish.maven
, add sonatype_platform: portal
.
targets:
java:
production_repo: ...
reverse_domain: com.example.api
publish:
maven:
sonatype_platform: portal
Add namespace (Central Portal only)
-
Add a namespace on Sonatype Portal
The namespace will be part of your package's name. It will be the inverse of the domain that you own. i.e.
tld.domain.subdomain
-
Copy down the Verification Key
You will be able to prove your ownership of the namespace by adding a TXT record of the verification key to your domain.
Create a Sonatype Jira ticket (OSSRH only)
-
Make an account on Sonatype Jira
You’ll likely want to use a group email address (for example, dev@ or sdks@) and put the password in your shared password manager, rather than tie the account to one individual. This is the account that owns your published SDKs and it’s a bit tricky to move ownership later.
-
Create a one-time package setup ticket
- This is to create the Sonatype repositories and permissions used to publish the package to Maven Central. This request should not be made until we have a public GitHub repo for the package, because the Sonatype team may manually review the metadata in the source code before approving the package.
- The summary and description can just mention that you are creating a new project and its name.
- Group Id, most likely your reverse domain (for example,
com.mycompanyname
). - Project URL and SCM url should be the location of the Java SDKs on GitHub.
- Username, include both
stainless-dev
and your username on Sonatype Jira. (This allows us to push and publish changes on your behalf.) - Already synced to central, almost certainly “No”, unless you are migrating a pre-existing Java SDK to Stainless.
Prove ownership over your domain
Add a temporary TXT record to the DNS for your primary domain (the reverse of your groupId) to verify that the person registering this Java group actually controls the domain.
If using the Central Portal flow, the contents of the TXT record is the verification key provided by Sonatype.
If using the OSSRH flow, the contents of the TXT record is the ID of the JIRA ticket created in the previous step (for example, OSSRH-12345
).
Generate user token (Central Portal only)
From the Sonatype dashboard, generate a user token XML file.
Extract <username>…</username>
and <password>…</password>
from the XML file and store them somewhere secure.
<server>
<id>${server}</id>
<username>//P7KNy5</username>
<password>+8sEiCiUrSoODM/S4yFhiKqUWJzS1lDbcac5I7hVzPS4</password>
</server>
Set up PGP package signing
-
Install GnuPG.
-
In a terminal, run
gpg --gen-key
. You are prompted to enter your name, email, and a passphrase for the keypair. -
Run
gpg --list-signatures --keyid-format 0xshort
(Central Portal only)Write down the hex key-id
0x147A5BF0
somewhere.$ gpg --list-signatures --keyid-format 0xshort
pub ed25519/7FAD9FAA 2023-08-02 [SC] [expires: 2026-08-01]
418D41921938A753CAAE57985114AD037FAD9FAA
uid [ultimate] Your Organization <you@yourorg.com>
sig 3 0x147A5BF0 2023-08-02 [self-signature] -
Run
gpg --list-keys --keyid-format short
:% gpg --list-keys --keyid-format short
[keyboxd]
---------
pub ed25519/7FAD9FAA 2023-08-02 [SC] [expires: 2026-08-01]
418D41921938A753CAAE57985114AD037FAD9FAA
uid [ultimate] Your Organization <you@yourorg.com>
sub cv25519/07EB38A7 2023-08-02 [E] [expires: 2026-08-01] -
Export the key in ASCII-armored format (
7FAD9FAA
is the short key ID in this example).$ gpg --export-secret-keys --armor 7FAD9FAA
-----BEGIN PGP PRIVATE KEY BLOCK-----
lIYEZMpnEhYJKwYBBAHaRw8BAQdA1FQMKz+wwliKNdLehegZP0QiaKrZJqADNyVn
VCUzIrD+BwMCwZrqVbVPfSr8NwxEh3M6kWtMGmnLMOk/NWVe7dtCxDxo37l/Ncxj
Mm9EZiH6WXwoXXq20nOW354oNOVz/UPvDU+oaRDDUM9SYs392i69WLQjWW91ciBP
cmdhbml6YXRpb24gPHlvdUB5b3Vyb3JnLmNvbT6ImQQTFgoAQRYhBEGNQZIZOKdT
yq5XmFEUrQN/rZ+qBQJkymcSAhsDBQkFo5qABQsJCAcCAiICBhUKCQgLAgQWAgMB
Ah4HAheAAAoJEFEUrQN/rZ+qgtsBAMCBuTqYEJljxStRO7SsMLWOc47CIIXD0Yid
CbySBX0ZAP9DXuuGVYbHFONvHxNKszu2hY9A1BbRuNjeGeWuVOw9ApyLBGTKZxIS
CisGAQQBl1UBBQEBB0AFxkZ+ZdEN7Epwri/w5ETAf+MOqdwAP2sS6TccSjEiXQMB
CAf+BwMCtKG1TBUSC/z8tn761I5j+ifVIuMqdQPYIhZtjvIyC+NyrBi0j1ZtUG4A
DAeDKNyM63uyb7omOH8+Lu0J71SGhVnZWszUOf3rrT/TA5MktYh+BBgWCgAmFiEE
QY1Bkhk4p1PKrleYURStA3+tn6oFAmTKZxICGwwFCQWjmoAACgkQURStA3+tn6qa
XAD/W2ucVURngmCUiUtdjQAZz36yQYPQmBhcdabZMyXKHz0A/itwYkuRbD2mp4p/
xJk/QLXs/2/xBA6s0ROVVspy6MEA
=p/g/
-----END PGP PRIVATE KEY BLOCK----- -
Publish your gpg public key. (Using the same
7FAD9FAA
from above as key ID example).$ gpg --keyserver keyserver.ubuntu.com --send-keys 7FAD9FAA
Add Sonatype credentials and PGP secret key to Java/Kotlin GitHub repository
- In your GitHub repository, navigate to Settings > Secrets and Variables > Actions.
- Click New Repository Secret.
- Set Name to
{MY_ORG}_SONATYPE_GPG_SIGNING_KEY
(replace{MY_ORG}
with your organization name). - In Secret, paste the PGP private key block from
gpg --export-secret-keys --armor <keyid>
. - Click Add Secret.
-
Following the same process, add these secrets:
{MY_ORG}_SONATYPE_GPG_SIGNING_KEY_ID
(Central Portal only)- The hex key-id you have generated earlier, i.e.
0x147A5BF0
.
{MY_ORG}_SONATYPE_GPG_SIGNING_PASSWORD
- The passphrase you entered when creating the keypair.
{MY_ORG}_SONATYPE_USERNAME
{MY_ORG}_SONATYPE_PASSWORD
- Your username and password for your Sonatype account (OSSRH) or your Sonatype user token (Central Portal).
- The hex key-id you have generated earlier, i.e.
Go: GitHub
Go installs packages from source, so nothing other than the GitHub repository is required for setup. We automatically request updates from the Go package index which updates your godoc on a release.
Versioning and releases
Whenever we generate a new change for your SDK, we create and merge a PR into the next
branch in your
production
repository. Each commit should describe the related change using the Conventional
Commits format.
A Release PR is then created against the main
branch, which collects individual changes until you are
ready to release them. The PR waits for a code owner's review and merges automatically upon approval.
Your first release will be Release 0.1.0-alpha.1
, meaning that the first release published to your package
manager will have an alpha tag.
Stainless will increment the version used in each subsequent release PR based on the prior one. We use the semantic information of the commits in the release to find the next available version. We highly recommend using Conventional Commits to ensure versioning is correct and automatic:
- Breaking changes increment the major version number (if and only if the version is already at least
1.0.0
) - Features increment the minor version number
- Fixes increment the patch number
You can override our suggested version by modifying the PR title. Doing so will propagate your provided version (including any alpha or beta tags) to the release in Github and your package manager. We recommend:
- Staying in the alpha or beta stage while your SDKs still have diagnostic errors
- Staying in the 0.0.x range while your SDKs still have diagnostic warnings
- Staying in the 0.x.y range while your SDKs still have unacknowledged diagnostic notes
- Moving to 1.0.0 once your SDK has none of the above
We use semver-valid version numbers for releases.
Development and release flow
Stainless pushes code to various GitHub repos:
- Stainless config repo
- Stainless SDK repos
- Your production repos
Release flow
Stainless uses a few branches in your production repository to manage the release process:
main/master
: The target branch of your repository. This defaults tomain
but can be configured per language usingproduction_repo
.next
: This branch is used to collect changes for the next release. Stainless will create Release PRs based on the changes in this branch.generated
: The branch where Stainless pushes generated code from the Studio. This branch represents the latest generated code before any custom code changes are applied.release-please--*
: Temporary release branches created and managed by our GitHub App. These branches are based onnext
and are used to create release PRs.