Dive into the power of Lemon Squeezy as we take a journey through setting up a fully functional SaaS App with subscriptions using Next.js App Directory. In this hands-on tutorial, you'll learn how to create an API key, display products in a pricing table using TailwindUI, and manage subscriptions with Lemon Squeezy.
We'll also cover how to handle Lemon Squeezy webhook events, using zod for input parsing, and how to store subscription updates in a Postgres database using drizzle ORM. Additionally, you'll learn how to synchronize product data between Lemon Squeezy and your own database, and manage user subscriptions using Vercel's server actions.
By the end of this guide, you'll be equipped with the skills to create a robust subscription setup, leveraging Lemon Squeezy's functionalities and a powerful tech stack. Let's get started!
Setting up Lemon Squeezy 🍋
In order to get started you should have created a store in Lemon Squeezy as well as some products and variants. In this tutorial I will focus on subscriptions, but it should work equally well for other products.
Next, let's generate an API Key at https://app.lemonsqueezy.com/settings/api to connect to our store:
Add this as an environment variable to your Next.js project:
Creating a Dynamic Pricing Table with Product Info
Now that we've laid the groundwork, our next step involves fetching all the product and variant information via API and presenting it in a pricing table. I am a huge fan of TailwindUI so I picked one of their pricing tables from here. This is what our final pricing table will look like:
First, we need to fetch all the products with the
getProductVariants function, which also has the
createRequestOptions utility functions to build out the request:
Furthermore, with the help of GPT4 I also quickly created a
SLemonSqueezyRequest and the corresponding type
TLemonSqueezyRequest to help me parsing the API output and enhanced type safety and auto-completion functionality with the data:
With the function and zod models ready, I created a
pricing.tsx component to fetch all the data, which I then pass to the pricing table. One more important convenience function I created is the
createCheckoutLink function to generate the hosted checkout link.
Finally, I ran into a small problem when I tried to show the variant description with checkmarks in my pricing table:
To do this, I used the JSDOM parser to pull out all the feature elements:
When you're satisfied with your pricing table in the
dev environment, it's easy to move the products from
test mode to
live mode. All you need to do is create a new
API key for the live environment, add it to your environment variables, and you're done with the pricing table! 🥳
Listening to Subscription Webhook Events
Now that the pricing table is ready, we need to know about any new subscription updates in our app to manage access and such. To do this, we can create a
Route Handler. It listens for certain Lemon Squeezy Webhook Requests and saves the data in our database. Then, we can use this info to develop any logic we want.