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.
In order to sell a package, it needs to be kept private. There are two common techniques:
What would a workflow look like that has very little friction?
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:
(Example command only)
Want to sell your package or develop a platform? Buy our Next.js implementation!
Stripe account required.
The pitch
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!
This is a barebones Next.js template for selling private NPM packages with good ergonomics and easy setup.
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:
We believe that these bad ergonomics are the reason selling packages is not catching on.
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.
✅ 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
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.
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
:
GITHUB_USER_OR_ORG=remotion-dev
write:packages
scope. Other scopes will automatically be selected.GITHUB_TOKEN
to your .env
.GITHUB_TOKEN=...
Product Information -> Additional options -> Metadata
, add:
repo
, set the name of your repository. It must be the same name as in your package.json (4).https://your-domain.com/thanks?id={CHECKOUT_SESSION_ID}
. Replace your-domain.com
with the deployment of the app.PAYMENT_LINK
environment variable in .env
.PAYMENT_LINK=https://buy.stripe.com/test_14k4hJbNK
~/.npmrc
(the global NPM config) and add the following line://npm.pkg.github.com/:_authToken=[GITHUB_TOKEN]
Replace [GITHUB_TOKEN]
with the token you generated in (1).
package.json
as follows:
name
to @your-username-or-org/package-name
.repository
must be the package name and the user or organization name will be the scope.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"
}
}
STRIPE_KEY
to your .env
.STRIPE_KEY=sk_test_51IJe
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!
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.
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
.
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.