{"id":2306,"date":"2026-07-20T12:41:36","date_gmt":"2026-07-20T10:41:36","guid":{"rendered":"https:\/\/kindsonthegenius.com\/blog\/how-to-build-and-publish-python-sdk-package-to-npm\/"},"modified":"2026-08-27T17:47:00","modified_gmt":"2026-08-27T15:47:00","slug":"how-to-build-and-publish-python-package","status":"publish","type":"post","link":"https:\/\/kindsonthegenius.com\/blog\/how-to-build-and-publish-python-package\/","title":{"rendered":"How to Build and Publish a Python Package (and When npm Fits)"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\"><em>Learn how to build and publish a Python package to PyPI, from project structure and pyproject.toml to building, testing, and publishing your package.<\/em><\/p>\n\n\n<p><!-- ktg-updated-banner --><\/p>\n<p><em>Updated August 2026 \u2014 full tutorial restored for this URL.<\/em><\/p>\n<h2>TL;DR<\/h2>\n<ul>\n<li>\n<p><strong>Python packages<\/strong> are typically published to <strong>PyPI<\/strong>, while JavaScript and TypeScript packages are published to npm.<\/p>\n<\/li>\n<li>\n<p>Use a clean <strong><code>src<\/code> project layout<\/strong> with <code>pyproject.toml<\/code> to define your package metadata, dependencies, and build system.<\/p>\n<\/li>\n<li>\n<p><strong>Build your package<\/strong> into distributable <code>.whl<\/code> and <code>.tar.gz<\/code> artifacts before publishing.<\/p>\n<\/li>\n<li>\n<p><strong>Test on TestPyPI first<\/strong> to verify that your package can be installed and works as expected.<\/p>\n<\/li>\n<li>\n<p>If you also provide a <strong>JavaScript SDK<\/strong>, publish it separately to npm and manage its versioning independently from the Python package.<\/p>\n<\/li>\n<\/ul>\n<p>The URL slug says <strong>Python SDK \u2026 to npm<\/strong>. Clarification up front:<\/p>\n<ul>\n<li><strong>Python libraries<\/strong> publish to <strong>PyPI<\/strong> (<code>pip install \u2026<\/code>).<\/li>\n<li><strong>npm<\/strong> is for JavaScript\/TypeScript packages. You only publish to npm if you also ship a <strong>JS client SDK<\/strong>.<\/li>\n<\/ul>\n<p>This tutorial focuses on a proper Python package on PyPI, then notes the npm path for a companion JS SDK.<\/p>\n<ol>\n<li><a href=\"#t1\">Project layout<\/a><\/li>\n<li><a href=\"#t2\">pyproject.toml<\/a><\/li>\n<li><a href=\"#t3\">Build artifacts<\/a><\/li>\n<li><a href=\"#t4\">Publish to PyPI (or TestPyPI)<\/a><\/li>\n<li><a href=\"#t5\">Optional: JS SDK on npm<\/a><\/li>\n<\/ol>\n<p><strong id=\"t1\">1. Project layout<\/strong><\/p>\n<pre><code>my_sdk\/\n  pyproject.toml\n  README.md\n  src\/my_sdk\/__init__.py\n  src\/my_sdk\/client.py\n  tests\/test_client.py\n<\/code><\/pre>\n<p><strong id=\"t2\">2. pyproject.toml<\/strong><\/p>\n<pre><code>[build-system]\nrequires = [\"setuptools&gt;=61\", \"wheel\"]\nbuild-backend = \"setuptools.build_meta\"\n\n[project]\nname = \"my-sdk\"\nversion = \"0.1.0\"\ndescription = \"Example Python SDK\"\nreadme = \"README.md\"\nrequires-python = \"&gt;=3.9\"\ndependencies = [\"requests&gt;=2.31\"]\n\n[tool.setuptools.packages.find]\nwhere = [\"src\"]\n<\/code><\/pre>\n<p><strong id=\"t3\">3. Build artifacts<\/strong><\/p>\n<pre><code>python -m pip install build twine\npython -m build\n# creates dist\/*.whl and dist\/*.tar.gz\n<\/code><\/pre>\n<p><strong id=\"t4\">4. Publish to PyPI (or TestPyPI)<\/strong><\/p>\n<pre><code># Test first\npython -m twine upload --repository testpypi dist\/*\npip install -i https:\/\/test.pypi.org\/simple\/ my-sdk==0.1.0\n\n# Production\npython -m twine upload dist\/*\n<\/code><\/pre>\n<p>Use API tokens from pypi.org \u2014 never commit passwords.<\/p>\n<p><strong id=\"t5\">5. Optional: JS SDK on npm<\/strong><\/p>\n<p>If your product needs a browser\/Node client, create a separate <code>packages\/js-sdk<\/code> with <code>package.json<\/code>, build with tsc, then:<\/p>\n<pre><code>npm login\nnpm publish --access public\n<\/code><\/pre>\n<p>Keep Python (PyPI) and JS (npm) versioned independently; document both in the monorepo README.<\/p>\n<h2>Final Thoughts<\/h2>\n<p>Publishing a Python package is more straightforward when you treat packaging and distribution as part of the project from the beginning. A clean structure, a properly configured <code>pyproject.toml<\/code>, and a repeatable build process give users a reliable package they can install and use.<\/p>\n<p>For Python libraries, <strong>PyPI is the natural distribution channel<\/strong>. npm only becomes relevant when your product also includes a JavaScript or TypeScript SDK, in which case the two packages should be maintained and versioned independently.<\/p>\n<p>Before publishing to production, test your package through TestPyPI, verify the installation, and protect your publishing credentials with API tokens. These simple steps can prevent avoidable release problems as your package grows.<\/p>\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Learn how to build and publish a Python package to PyPI, from project structure and pyproject.toml to building, testing, and publishing your package. Updated August &hellip; <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"pagelayer_contact_templates":[],"_pagelayer_content":"","footnotes":""},"categories":[35],"tags":[],"class_list":["post-2306","post","type-post","status-publish","format-standard","hentry","category-algorithms"],"acf":[],"_links":{"self":[{"href":"https:\/\/kindsonthegenius.com\/blog\/wp-json\/wp\/v2\/posts\/2306","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/kindsonthegenius.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/kindsonthegenius.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/kindsonthegenius.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/kindsonthegenius.com\/blog\/wp-json\/wp\/v2\/comments?post=2306"}],"version-history":[{"count":4,"href":"https:\/\/kindsonthegenius.com\/blog\/wp-json\/wp\/v2\/posts\/2306\/revisions"}],"predecessor-version":[{"id":2490,"href":"https:\/\/kindsonthegenius.com\/blog\/wp-json\/wp\/v2\/posts\/2306\/revisions\/2490"}],"wp:attachment":[{"href":"https:\/\/kindsonthegenius.com\/blog\/wp-json\/wp\/v2\/media?parent=2306"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/kindsonthegenius.com\/blog\/wp-json\/wp\/v2\/categories?post=2306"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/kindsonthegenius.com\/blog\/wp-json\/wp\/v2\/tags?post=2306"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}