API StudioSDK StudioMonitoringMCP ServerSpec AuditFeatures
ComparePricingBlogDocs
Log inStart for free
API StudioSDK StudioMonitoringMCP ServerSpec AuditFeatures
ComparePricingBlogDocs
Log inStart for free
API StudioSDK StudioMonitoringMCP ServerSpec AuditFeatures
ComparePricingBlogDocs
Log inStart for free
Blog/Guides
Guides·September 8, 2026·5 min read

Publishing SDKs to npm, PyPI, Maven Central and the rest

Seven registries, seven sets of rules, and two languages that have no registry at all. The decisions you cannot take back are all made before the first release.

#sdks#publishing#npm#package-registries
Publishing SDKs to npm, PyPI, Maven Central and the rest

Generating a client library is the easy half. Getting it into the place your users already look, under a name you can live with, is where the irreversible decisions are.

Most of them are naming decisions, and every registry punishes a bad one differently.

The registries, and what each wants

npm, for TypeScript. Scoped (@acme/api) or unscoped (acme-api). Take the scope. It is namespaced to your organisation, it cannot be squatted, and it reads unambiguously beside your other packages. npm has no rename, and it refuses to republish a version you have deleted, so the first publish claims the name permanently.

PyPI, for Python. The distribution name is what users type after pip install. It is normalised, so acme_api and acme-api are the same name to the index and you cannot have both. The import name is a separate thing and does not have to match, which surprises people: pip install acme-api giving you import acme_api is normal and fine.

Maven Central, for Java and Kotlin. Coordinates are groupId:artifactId, and the groupId must be a domain you control. Sonatype verifies it before your first release, not after. com.acme means proving you own acme.com. This is the single longest lead time in any SDK launch and it is the one nobody schedules for, because every other registry lets you publish in five minutes.

crates.io, for Rust. Flat namespace, no scopes, first come first served. Names are effectively permanent. Reserve yours early even if you are not ready to publish.

RubyGems, for Ruby. Flat namespace too. Convention is dashes in the gem name and slashes in the require path.

Packagist, for PHP. vendor/package, wired to a git repository rather than an upload. Composer resolves from tags, so your release process is a tagging process.

pub.dev, for Dart. Flat namespace, and it scores packages publicly on documentation and maintenance. That score is on the page your users read, so the README is not optional in the way it is elsewhere.

Go and Swift have no registry

This catches people out because it inverts everything above.

Go modules and Swift Package Manager resolve straight from a git repository. There is no account to connect, no upload, no publish step. You push a tagged commit and go get finds it.

Which sounds simpler and is more dangerous, because of one thing:

For Go, the repository URL is the import path. Go derives the module path from the repo and writes it into go.mod, so github.com/acme/acme-go is the line every consumer types at the top of their file. Rename or move that repository and every import breaks, for everyone, with no deprecation path and no redirect. There is no equivalent of an npm deprecation notice.

Pick the Go repository name deliberately, before the first tag, and expect it to differ from the repository your other languages use. acme-go is a repository name. acme-node is a different one. They should not be the same repo.

One repo per language, or one repo for all

Both work. The tradeoffs are not symmetric.

Separate repositories per language are the default for a reason: Go forces it (the import path is the repo), release tags do not collide, each language gets its own issue tracker, and a consumer cloning your Python SDK does not download six other languages.

A monorepo is tidier for you and worse for them. If you go that way, Go still needs its own, so you end up with a monorepo plus an exception, which is usually the worst of both.

What to settle before the first publish

A short list, all of it permanent or expensive to change:

The package name in every registry. Check availability everywhere at once, before you pick. Discovering that your name is taken on crates.io after you have shipped on npm means either an inconsistent set of names or a rename.

The Maven groupId, and start the verification. It gates your Java launch and it is out of your hands.

The Go repository. See above.

The version you start at. 1.0.0 is a claim about stability. 0.1.0 buys room to change the shape of the client while people are still evaluating. Starting at 1.0.0 because it looks committed is how teams end up doing a major bump in month two.

Who owns the credentials. Registry tokens are long-lived and they publish under your organisation's name. They belong in your secret manager with an owner, not in one engineer's shell profile.

Automating it

Publishing by hand works exactly until the release where somebody forgets one language, and then you have five SDKs on 2.1.0 and one on 2.0.4, and the one that lagged is the one someone reports a bug against.

The property worth having is that a release is one action producing every package, with the version coming from a single source rather than from six manual edits. If your version lives in your OpenAPI document and propagates into every generated manifest, the manifests cannot disagree with each other.

On Octri, connecting each registry account is a one-time step and releases go out on publish, with Go and Swift handled through the GitHub App rather than a registry token. Automatic publishing is a Business-tier feature; on the tiers below it, the packages are generated and you publish them yourself, which is the same artifacts with a manual last step.

Before you press publish

Read the package. Not the code, the packaging: what files are included, whether the README renders, whether the license is there, whether the version matches what you think you are shipping. Every registry makes at least one of those easy to get wrong, and all of them are visible on the page your users land on.

If you have not decided which languages to ship yet, the OpenAPI to TypeScript SDK and OpenAPI to Python SDK pages show what the generated client looks like at the call site in each. And before any of it, the spec audit tells you whether your document is in a state to generate something worth publishing.

← Previous41% of APIs drift within 30 days, and most of it is invisible
Next →Should you hand-write your SDKs or generate them?

Related articles

Documenting webhooks in OpenAPI 3.1, and the half it cannot describe
Guides·5 min read

Documenting webhooks in OpenAPI 3.1, and the half it cannot describe

3.1 finally gave webhooks a home in the spec. It describes the payload, which is the easy part, and says nothing about delivery, which is where integrations break.

September 11, 2026
API-first in practice: what changes when the spec is the source of truth
Guides·5 min read

API-first in practice: what changes when the spec is the source of truth

The phrase is used to mean four different things. Only one of them changes how your team works, and it is the one that makes the spec a build input rather than a report.

September 10, 2026
Getting your API docs cited when someone asks an AI about your product
Guides·6 min read

Getting your API docs cited when someone asks an AI about your product

People are asking assistants what your API does before they visit your site. What gets quoted back is decided by how your docs are structured, not by a file at your root.

September 8, 2026
Your MCP server needs documentation, and it is not your API docs
Guides·5 min read

Your MCP server needs documentation, and it is not your API docs

There is no spec format for MCP servers yet, so what an integrator gets is a README and a config snippet. Here is what actually has to be in it.

September 7, 2026

A letter when something ships

New SDK languages, changes in the generator, and now and then a longer piece on keeping docs from rotting. Roughly one a month.

Join developers keeping tabs on Octri.

Octri

Upload an OpenAPI spec. Get complete docs and production-ready SDKs in 10 languages, live in minutes.

Contact support

Product

  • API Studio
  • SDK Studio
  • Monitoring
  • MCP Server
  • Pricing
  • Compare
  • Blog
  • Changelog
  • Press Kit

From your spec

  • Spec Audit
  • TypeScript SDK
  • Python SDK
  • Go SDK
  • Java SDK
  • MCP Server

Developers

  • Documentation
  • API Reference
  • SDK Libraries
  • MCP Server
  • Monitoring
  • CLI
  • Support

Legal

  • Terms of Service
  • Privacy Policy
  • Fair Use Policy
  • Data Processing (DPA)
  • Cookie Policy
  • Security
  • Subprocessors

© 2026 Octri, LLC. All rights reserved.

Made by devs who got tired of hand-writing SDKs.