Build and deploy Next.js app with Vercel and Supabase
Get a step-by-step overview of how to build a Next.js app with Paddle Billing, including a localized pricing page, integrated inline checkout, and screens for customers to manage their payments.
Next.js is an open source web development framework that you can use to create high-quality web apps. It's built on top of React, a popular JavaScript library for building user interfaces, and includes a range of features designed to make building web apps easier.
You can use our Paddle Billing SaaS starter kit to quickly create and deploy a Next.js app that includes everything you need for subscription billing — including a localized pricing page, integrated checkout, auth and user management, and screens for customers to manage their payments.
What are we building?
In this tutorial, we'll create a Next.js app that's integrated with Paddle Billing and deploy it to Vercel. Our app includes:
- A beautiful, three-tier pricing page that's fully localized for 200+ markets.
- A high-converting checkout that's fully integrated with your app, built with Paddle Checkout.
- User management and auth handled by Supabase.
- Ready-made screens to let customers manage their payments and subscriptions.
- Automatic syncing of customer and subscription data between Paddle and your app using webhooks.
Check out the demo at paddle-billing.vercel.app.
We'll learn how to:
- Set up Paddle Billing in sandbox.
- Create a notification destination for syncing data.
- Create products and prices for our SaaS app.
- Configure and deploy a Next.js app to Vercel.
- Take a test payment.
- Transition from sandbox to live.
Before you begin
Sign up for Paddle
Paddle Billing is a complete digital product sales and subscription management platform, designed for modern software businesses. Our API-first platform takes care of payments, localization, and subscription management for you.
You'll need a Paddle account to get started. There are two kinds of Paddle account:
- Sandbox — for testing and evaluation
- Live — for selling to customers
For this tutorial, we recommend signing up for a sandbox account. You can transition to a live account later when you've built your integration and you're ready to start selling.
If you sign up for a live account, you'll need to complete account verification. This is where we ask for some information from you to make sure that we can work together. While we're verifying your account, you can't launch a checkout or sell on the Paddle platform.
Sign up for Vercel and Supabase
As part of our tutorial, we're going to deploy our app to Vercel and use Supabase.
- Supabase is a developer platform that includes databases, authentication, and other features. Our app integrates with Supabase to handle user management and authentication, as well as syncing customer data with Paddle Billing using webhooks.
If you don't have Vercel and Supabase accounts, you'll need to sign up — it's free to get started.
You'll also need a Git provider to store the code that powers your app. When deploying to Vercel, the deployment screen walks you through setting up an account with GitHub (recommended), GitLab, or Bitbucket, if you don't already have one.
Set up your local environment
To work on the starter kit locally, you'll need an IDE like Visual Studio Code and:
- Node.js version >
20
You don't need to set up your local development environment to get a working demo on Vercel, so you can come back to this later when you're ready to start building.
Overview
Create and deploy a Next.js app integrated with Paddle Billing in four steps:
Clone the Git repo, integrate with Supabase, configure Paddle variables, and deploy.
Create products and prices in Paddle, then update your app to use them.
Add your website to Paddle, then give your app a spin — take a test payment and explore the customer billing screens.
Build your app, then transition to live
Build your app on top of our starter kit, then transition your Paddle Billing account to live to start selling.
1. Start deploy to Vercel
To create a Vercel project ready for us to set up, click the button to get started:
Create Git repo
First, create a clone of our starter kit repo. This creates a copy of the code in a repo in your Git provider account, so you can build your app on top of our project.
Click the Continue with GitHub, Continue with GitLab, or Continue with Bitbucket buttons to connect your Git provider to Vercel, if you haven't already. Then, enter a name for your repo.
The repo name becomes the name of your project in Vercel, and it's also used for deploy preview URLs. If the name is taken, Vercel appends some characters to your project name when creating a deploy preview URL.
Integrate with Supabase
Next, click Add to walk through integrating with Supabase.
You can give your project any name. We recommend using a password manager to generate and store a secure password.
Make sure the Create sample tables with seed data box is checked. This creates tables in Supabase to store customer and subscription data for our app.
Configure Paddle variables
We need to supply some variables so that our app can interact with our Paddle account.
There are four variables that we need:
PADDLE_API_KEY | An API key, used for interacting with Paddle data in the backend. For example, syncing customer and subscription data with Supabase. |
NEXT_PUBLIC_PADDLE_CLIENT_TOKEN | A client-side key, used for interacting with Paddle in the frontend. For example, getting localized prices for pricing pages and opening a checkout. |
PADDLE_NOTIFICATION_WEBHOOK_SECRET | A secret key used for verifying that webhooks came from Paddle and haven't been tampered with in transit. Important for security. |
NEXT_PUBLIC_PADDLE_ENV | Environment for our Paddle account. sandbox for sandbox accounts; production for live accounts. |
Get an API key and client-side token
Client-side tokens and API keys are used for authentication. Paddle creates a default client-side token and API key when you sign up, but we recommend generating separate ones for our app.
Go Paddle > Developer tools > Authentication
Click Generate API key under the API keys section.
Give your key a name and description, then click Generate.
From the list of API keys, click the … action menu next to the key you just created, then choose Copy key from the menu.
Paste your key as
PADDLE_API_KEY
in the Deploy to Vercel screen.Head back to the authentication screen in Paddle, then click Generate client-side token under the Client-side tokens section.
Give your client-side token a name and description, then click Generate.
From the list of client-side tokens, click the … action menu next to the client-side token you just created, then choose Copy token from the menu.
Paste your key as
NEXT_PUBLIC_PADDLE_CLIENT_TOKEN
in the Deploy to Vercel screen.
To learn more about client-side tokens and API keys, see: Authentication
Treat your API key like a password. Keep it safe and never share it with apps or people you don't trust.
Create a webhook destination
You can use notifications to get webhooks from Paddle when something important happens in your Paddle system, like a customer is updated or a new subscription is created. We use webhooks in our app to keep our app in sync with Paddle, letting customers see and manage their subscriptions and payments.
To start receiving webhooks, create a notification destination. This is where you can tell Paddle which events you want to receive and where to deliver them to.
Go to Paddle > Developer Tools > Notifications.
Click New destination.
Give your destination a name.
Make sure notification type is set to webhook — this is the default.
Enter
https://<PROJECTNAME>.vercel.app/api/webhook
as your URL, where<PROJECTNAME>
is the name of your Vercel project. You can always rename this later. For example:https://paddle-billing.vercel.app/api/webhook
.Check the select all events box.
Click Save destination when you're done.
From the list of notification destinations, click the … action menu next to the notification destination you just created, then choose Edit destination from the menu.
Copy the secret key and paste it as
PADDLE_NOTIFICATION_WEBHOOK_SECRET
.
To learn more about webhooks and notification destinations, see: Create a notification destination
Set your environment
For NEXT_PUBLIC_PADDLE_ENV
, enter:
sandbox
if you're working with a sandbox accountproduction
if you're working with a live account
We recommend working with a sandbox account for this tutorial. Sandbox accounts are designed for testing and evaluation. Live accounts must be approved by Paddle before you can open checkouts for them.
Review and deploy
At this point, we've done everything that we need to deploy. Review your settings, then click Deploy.
Wait for Vercel to build. If everything went well, our build should complete successfully!
However, if we open our deploy preview link then our integration isn't ready yet — our pricing page doesn't display and prices and the buttons to get started don't work. We'll fix these in the next step.
2. Set up your product catalog
To make our app work properly with Paddle, we need to specify how products in our app map to products in Paddle.
Model your products and prices
A complete product in Paddle is made up of two parts:
- A product entity that describes the item, like its name, description, and an image.
- At least one related price entity that describes how much and how often a product is billed.
You can create as many prices for a product as you want to describe all the ways you bill for it.
Our template comes with a three tier pricing page, with plans for Free, Basic, and Pro. For each of these plans, there are monthly and annual options.
We can mirror this in Paddle, modeling this as three products with two prices for monthly and annual:
Product: Free
- Price: Free (monthly)
- Price: Free (yearly)
Product: Basic
- Price: Basic (monthly)
- Price: Basic (yearly)
Product: Pro
- Price: Pro (monthly)
- Price: Pro (yearly)
Create products and prices
You can create products and prices using the Paddle dashboard or the API.
Go to Paddle > Catalog > Products.
Click New product.
Enter details for your new product, then click Save when you're done.
Under the Prices section on the page for your product, click New price.
Enter details for your new price. Set the billing period to Monthly to create a monthly price.
Click Save when you're done.
Create another price, setting the billing period to Annually and Save.
Repeat for each of your products, until you have three products with two prices each.
To learn more products and prices, see: Create products and prices
Update pricing constants
Now we've created products and prices, we need to update our app with details of our new prices.
Clone your Git repo locally, then open src/constants/pricing-tier.ts
in your IDE. If you're using GitHub, you can use GitHub Desktop to clone a repo locally if you're not familiar with Git.
pricing-tier.ts
contains constants that we use in our pricing page and checkout. Swap the Price IDs starting with pri_
with price IDs for the prices we just created.
You can also edit
src/constants/pricing-tier.ts
directly on your Git platform if you've not set up your local development environment.
For example:
12345678910111213141516171819201export interface Tier {
2 name: string;
3 id: 'starter' | 'pro' | 'advanced';
4 icon: string;
5 description: string;
6 features: string[];
7 featured: boolean;
8 priceId: Record<string, string>;
9}
10
11export const PricingTier: Tier[] = [
12 {
13 name: 'Starter',
14 id: 'starter',
15 icon: '/assets/icons/price-tiers/free-icon.svg',
16 description: 'Ideal for individuals who want to get started with simple design tasks.',
17 features: ['1 workspace', 'Limited collaboration', 'Export to PNG and SVG'],
18 featured: false,
19 priceId: { month: 'pri_01hsxyh9txq4rzbrhbyngkhy46', year: 'pri_01hsxyh9txq4rzbrhbyngkhy46' },
20 },
You can get Paddle IDs for your prices using the Paddle dashboard:
Go to Paddle > Catalog > Products, then click the product you want to get a price ID for in the list.
Click the … action menu next to a price in the list, then choose Copy price ID from the menu.
Paste the ID as the value for
priceId.month
orpriceId.year
insrc/constants/pricing-tier.ts
.
Add all your price IDs, then commit and push your changes to the main
branch on Git.
Vercel automatically rebuilds your site at this point. You can hop over the Vercel dashboard to check on the build progress.
When it's done, your pricing page should display prices, but you won't be able to checkout just yet. This is our next step.
3. Add your website to Paddle and test
To keep the Paddle platform safe for everyone, you must add your website to Paddle before you can launch a checkout from it. This protects you as a seller, making sure that only you are able to sell your products.
Get your website approved
If you're using a sandbox account, website approval is instant. You'll need to add your domain, but our seller verification team don't check your website.
Website approval makes sure you own the domains where you use Paddle Checkout, and that the products sold meet the Paddle acceptable use policy.
Get your website approved using the Paddle dashboard:
Go to Paddle > Checkout > Website approval.
Click Add a new domain, enter your Vercel demo app link, then click Submit for Approval.
Wait for approval.
If you're using a sandbox account, your website is automatically approved right away. You should see a green status symbol that says "Approved."
For live accounts, website approval may take a few days while the Paddle seller verification team check your website to make sure you're able to sell with Paddle. For more information, see: Website verification FAQs
Set your default payment link
Your default payment link is a quick way to open Paddle Checkout for a transaction. It's also used in emails from Paddle that let customers manage their subscription. It's typically your checkout page, or another page that includes Paddle.js.
We'll set our default payment link to the checkout page in our starter kit.
Go to Paddle > Checkout > Checkout settings.
Enter your Vercel demo app link under the Default payment link heading.
Click Save when you're done.
To learn more about what a default payment link is for, see: Set your default payment link
Check your notification destination endpoint
If the name of our project name in Vercel is taken, Vercel appends some characters to your project name when creating a deploy preview URL.
Earlier, we entered https://<PROJECTNAME>.vercel.app/api/webhook
as the endpoint for our notification destination. If your deploy preview URL doesn't match your project name, update this URL in Paddle. You can find your deploy URL in your Vercel dashboard.
Test!
We're now ready to take a test payment! Open your Vercel demo site. You should notice that Paddle returns the prices you entered for each of your plans on your pricing page.
Click Get started to launch a checkout for a plan, then take a test payment.
If you're using a sandbox account, you can take a test payment using our test card details:
Email address | An email address you own |
Country | Any valid country supported by Paddle |
ZIP code (if required) | Any valid ZIP or postal code |
Card number | 4242 4242 4242 4242 |
Name on card | Any name |
Expiration date | Any valid date in the future. |
Security code | 100 |
After checkout is completed, head back to the homepage and click Sign in. Have a look at the subscriptions and payments pages. They pull information from Paddle about a customer's subscriptions and transactions.
If prices don't appear on your pricing page, the checkout doesn't load, or you get a message saying "Something went wrong," you can open your browser console to see any specific error messages from Paddle.js to help you troubleshoot.
Use
⌘ Command
+⌥ Option
+J
(Mac) orCtrl
+⇧ Shift
+J
(Windows) to quickly open your browser console in Google Chrome.
Common problems
Check that:
- You pushed all of your changes to the
main
branch on Git and Vercel deployed your project successfully. You can redeploy a project from the Vercel dashboard. - You created your products and prices correctly. Prices should be recurring, meaning that Paddle creates a subscription for them when checkout completes.
- The Paddle IDs for price entities that you passed are correct. Sandbox and live systems are separate, so make sure you're passing price IDs for the environment that you're working in.
- You added a default payment link to your checkout under Paddle > Checkout > Checkout settings > Default payment link, and that this matches the domain where you're testing.
- You set up a notification destination correctly. Your webhook endpoint should match your Vercel deploy URL +
/api/webhook
, for example:https://paddle-billing.vercel.app/api/webhook
. - You passed a valid client-side token as
NEXT_PUBLIC_PADDLE_CLIENT_TOKEN
. Client-side tokens starttest_
orlive_
. - You set the correct environment as
NEXT_PUBLIC_PADDLE_ENV
. This should besandbox
orproduction
. - You passed a valid API key as
PADDLE_API_KEY
. - The tables in Supabase were created successfully. If you completed checkout, you can check to see whether records for new subscriptions were created.
Use the Vercel or Supabase docs to troubleshoot specific problems with those platforms.
4. Build your app, then go to live
You're done! You can use this starter kit as a basis for building a SaaS app on Paddle Billing.
Once you've built your app, transition to a live account to start taking real payments.
Sign up for a live account, then follow our go-live checklist to transition from sandbox to live.
Update your Vercel environment variables so they're for your live account.
Create new schemas in Supabase for your live data.
Set up Paddle Retain to handle payment recovery.
Next steps
That's it! Now you've built a Next.js app with Paddle Billing and deployed it to Vercel, you might like to hook into other features of the Paddle platform.
Do more with Paddle.js
Our starter kit passes prices to Paddle.js to display localized pricing on our pricing page and open a checkout to create subscriptions. There are a bunch of properties and settings you can pass to Paddle.js that give you more control over how opened checkouts work.
For example, you can prepopulate a discount, set the language that Paddle Checkout uses, or restrict payment options shown to customers.
Build advanced subscription functionality
Paddle Billing is designed for modern SaaS businesses, letting you build workflows to pause and resume subscriptions, flexibly change billing dates, and offer trials.
Integrate with Paddle Retain
Paddle Retain combines world-class subscription expertise with algorithms that use millions of data points to recover failed payments, reduce churn, and proactively upgrade plans.
- Build and deploy Next.js app with Vercel and Supabase
- What are we building?
- Before you begin
- Sign up for Paddle
- Sign up for Vercel and Supabase
- Set up your local environment
- Overview
- 1. Start deploy to Vercel
- Create Git repo
- Integrate with Supabase
- Configure Paddle variables
- Review and deploy
- 2. Set up your product catalog
- Model your products and prices
- Create products and prices
- Update pricing constants
- 3. Add your website to Paddle and test
- Get your website approved
- Set your default payment link
- Check your notification destination endpoint
- Test!
- 4. Build your app, then go to live
- Next steps
- Do more with Paddle.js
- Build advanced subscription functionality
- Integrate with Paddle Retain