A new way to sell NPM packages

Selling NPM packages could be a great way for creators to earn money and in return make better software for buyers.

But almost nobody is doing it. We think it is because the process is too cumbersome for both parties.

NPM Kiosk is an idea for how the ergonomics can be improved - it is also a template for selling and installing private NPM packages without the need for private registries.

The problem with private packages

In order to sell a package, it needs to be kept private. There are two common techniques:

  • Running a private registry: The vendor sets up a private registry and asks the buyer to configure their NPM client to use it. The problem: Each machine touching the project needs to authenticate with the registry. Your other devices, your CI/CD, your hosting provider and the machines of your team members all need to authenticate or they can't work with the project at all. It requires work and coordination.
  • Inviting to a private repo: The buyers of the software are invited to a private GitHub repository by the vendor. Installing the software requires copy-pasting the files and fixing the discrepancies between the two formatting styles to make the linter happy. Updating is done by copy-pasting the changes manually.

Setting higher expectations

What would a workflow look like that has very little friction?

For maintainers:
Quick setup
Low fees and infra cost
Ability to revoke access

For buyers:
1-step setup across machines
No account creation required
Easy to update

Our design

We implemented a Next.js project that uses Stripe Payment Links and serverless functions to proxy private packages to the buyers. Stripe is the single source of truth, so no database is required. Example flow:

  • The customer visits the vendor website and decides to buy the package
  • They get taken to a Stripe Payment link and pay
  • They will be redirected to a confirmation page on the vendors website with the Stripe Checkout Session ID attached as a URL parameter.
  • The buyer will be shown a command to install the package:
npm i https://remotion.pro/timeline/1.0.0/cs_a1niK3e...

(Example command only)

  • Running this command will trigger a Next.js serverless function, which will parse the Stripe Checkout Session ID and check it's validity.
  • Through metadata that was added to the Stripe Product, the function determines the NPM package that was bought.
  • The NPM package is hosted on GitHub Packages and only accessible to the vendor. Using their GitHub token, the Tarball of the package gets fetched and forwarded to the NPM client which is currently trying to install the package.
  • The author of the package can publish a new version using the regular npm publish command. The buyer can upgrade by changing the version in the URL.
  • Should the buyer leak the private link, the author can revoke access by adding a metadata field to the payment in Stripe.
  • Optional "Try before you buy" feature: You can offer a user an installation link that is valid for 5 minutes. They can try the package but future installs will fail which will make committing the package to their project impractical.
  • Optional: The buyer may enter a GitHub username in the Next.js app and get an invitation to the repo. The input field is prefilled with their GitHub username obtained from the email entered during the checkout process.

Buy the template

Want to sell your package or develop a platform? Buy our Next.js implementation!

Next.js template - $40

Read README.md for free
Try the demo
Sell private NPM links
Revokable access
Charge for GitHub access
Can run on Vercel free tier
Try before buy feature
No private registries
No accounts
No databases
No platform fees

Stripe account required.

Pitch + Demo

The pitch

Remotion Logo

Made by Remotion: We build a framework for making videos programmatically. While making all code public on GitHub, we charge companies for using it through a clause in our license.

Naturally we are interested in ways to live inbetween open source and commercial software in ways that make sense.

Watch out for our templates distributed through NPM Kiosk coming soon!


Another feature of the NPM Kiosk: It will mirror the README.md from your repo and let users read it for free!


NPM Kiosk

This is a barebones Next.js template for selling private NPM packages with good ergonomics and easy setup.

Table of Contents


Selling NPM packages can be a much-needed source of income for open source maintainers. The current ways of doing so provide a bad experience for the buyer:

  • Installing from a private NPM registry requires creating an account for it and configuring NPM. You and all your team members have to do this, and your CI and hosting platform also need to be configured.
  • Giving access to source code requires manual importing, adjusting to the project style and makes it hard to upgrade.

We believe that these bad ergonomics are the reason selling packages is not catching on.

How it works

Your packages are privately hosted on GitHub Packages.
A user can purchase a package using a Stripe payment link.

After payment is done, the user will get a private link with which the package can be installed:

  "dependencies": {
    "@remotion-dev/timeline": "https://www.remotion.pro/timeline/1.0.0/a1SBFWhbgbGmjPMwB7VRCsJrUz6WBvTS8eGzL4prCPvkKADMdhyz0pby1h"

When this URL is called, the app will check if the hash in the URL is a valid Stripe checkout session ID and if the product was paid. If so, the tarball of the package will be fetched from GitHub packages and forwarded to the client.


✅ No private registry required: The user can install the package as if it was public.
✅ No accounts: The user can buy the package without creating an account and without authenticating NPM.
✅ Revokable access: If a user leaks a package link, you can invalidate it.
✅ Easy updates: The user can change the URL in their package.json and switch between versions easily.
✅ No platform fees: Only Stripe fees.
✅ No database required: With Stripe as the only backend, you don't need to worry about setting a database.
✅ Free hosting: The project can be run on a Vercel Hobby account.
✅ Customizable: Develop the template further to add your own features.

Extra features

✅ Favicon is automatically set from your GitHub profile.
✅ Has an UI for allowing users to get the source code
✅ GitHub username is automatically suggested based on checkout email
"GitHub-only mode": Sell only a GitHub repository


  • You have to pay for the GitHub packages bandwidth and not exceed their storage limit.
  • The user needs to save the payment link after checkout, otherwise they will lose access to the paid package ➡️ You can add an email sending API to send the link to the user.
  • This template assumes out of box that you sell packages hosted in a single account or organization. The package name must be the same as the repository name.


Environment variables

5 environment variables are needed:

  • GITHUB_USER_OR_ORG: The name of your account or organization (0)
  • GITHUB_TOKEN: Must be a personal access token with write:packages scope (1)
  • STRIPE_KEY: Your Stripe API key, can be live or test mode. (5)
  • PAYMENT_LINK: The URL of your Stripe payment link. (3)
  • REPO_NAME: Used to display the README of the repository. (6)
  • TRY_BEFORE_BUY_SECRET: Secret for the "Try before you buy" feature. (7)

You can rename the .env.example file to .env to have a template.

(0) Select a user account or organization

Your packages must live in a singular GitHub personal scope or organization. Choose one and add it as GITHUB_USER_OR_ORG to your .env:


(1) Generate a GitHub personal access token

  1. Go to https://github.com/settings/tokens/new.
  2. Give a name and expiration date to your token.
  3. Select the write:packages scope. Other scopes will automatically be selected.
  4. Generate the token and add it as GITHUB_TOKEN to your .env.

(2) Create a Stripe product

  1. Go to https://dashboard.stripe.com/products/create to create a new product.
  2. Under Product Information -> Additional options -> Metadata, add:
    • For the key repo, set the name of your repository. It must be the same name as in your package.json (4).
    • Don't include your username or organization name.
  3. Note the default is recurring payment. Set it to one-time instead.
  4. Create the product and remember the name.

(3) Create a Stripe payment link

  1. Go to https://dashboard.stripe.com/test/payment-links/create to create a new payment link.
  2. In the "After payment" tab, select "Don't show confirmation page" and enter https://your-domain.com/thanks?id={CHECKOUT_SESSION_ID}. Replace your-domain.com with the deployment of the app.
  3. Create the product and add the PAYMENT_LINK environment variable in .env.

(4) Publish a package to GitHub packages

  1. Open your ~/.npmrc (the global NPM config) and add the following line:

Replace [GITHUB_TOKEN] with the token you generated in (1).

  1. Update the package.json as follows:
    • Set the name to @your-username-or-org/package-name.
    • The repository must be the package name and the user or organization name will be the scope.
    • The publishConfig must point to the GitHub registry.
  "name": "@remotion-dev/timeline",
  "repository": "https://github.com/remotion-dev/timeline",
  "publishConfig": {
    "registry": "https://npm.pkg.github.com"

(5) Get a Stripe key

  1. Go to https://dashboard.stripe.com/apikeys to get your production Stripe API key or to https://dashboard.stripe.com/test/apikeys to get a test API key. Both environments are supported without any further configuration needed
  2. Add the secret key as STRIPE_KEY to your .env.

(6) Set the repository name

Set the REPO_NAME environment variable in your .env to the repo name for which you'd like to render the README.md contents on the homepage. Making the README public can help your custumers be confident that your package solves their need before buying it. Do not include the username or organization name, this is already set using GITHUB_USER_OR_ORG.


Start the development server:

npm run dev


Connect the app to Vercel and deploy it. Set the right environment variables, and you're off!

Deploy with Vercel

Try before you buy (7)

You can allow users to try your package before they have to pay. Set the environment variable TRY_BEFORE_BUY_SECRET with any secret and users will be shown a "Try" command that is valid for 5 minutes.

They can get as many tries as possible, but it is impractical to commit this link to the repo as subsequent installs will fail. However, it is relatively trivial to copy the package from node_modules into their root folder and "vendor" the package that way.

Revoking access

In some cases, you want to revoke access for a user. For example, if they leaked their package link publicly or if they are using the package in a way that violates the license.

Go to https://dashboard.stripe.com/payments and find the payment of the customers to whom you want to revoke access.

On the payment page, under metadata, add another entry with the key invalid and value true.

Sell a GitHub repo only

Add the environment variable DISABLE_NPM with the value true to your .env file. This will disable the NPM feature completely and is useful if you want to sell a GitHub template!


We give you permission to use this repo to sell your own packages or continue developing it into your own platform.

You may modify the code and are not required to open source your modifications.

Do not make this repo public or sell it to others.

This repository comes with no warranty. We are not responsible for any damages caused by this repository.