Lemon Squeezy x Supabase x Next JS - Part 3

Prepare Server Component to generate the Pricing display


The complete guide is a work in progress, this third part has been completed.

This is part three of the guide, for the full guide, start here

If you are looking for a guide to help you out with setting up your very own Subscription using Next.JS, Lemon Squeezy and Supabase, you have come to the right place. In this first guide, we will look at how you can fetch products from Lemon Squeezy, so that you can populate your pricing table!

This guide is specifically created for Subscriptions with one product and multiple variants. You can see the difference in pricing strategy here.

The goal of this guide is that by the end you will be able to fetch your own products using Next.js 13 App Router.

Creating server component

As the Dialog component can not be used in a Server Component, we have created a seperate component that uses the "use client" at the start of the code.

To be able to render the client component in a server generated page (which helps for SEO), we will need to render this component with server information.

From the page.tsx page we will render the Pricing.tsx component, this component will be discussed on this part of the guide.

The Server Component Code

In the previous part of the guide, we have generated the Client component, which had 4 different parameters. In the Server component we will need to send the server data and pass it to the client component. We can do so by using the four parameters:

  • productVariants
  • company_id
  • user
  • store_id

Pricing.tsx code

  import { getProductVariants } from "./variants";
  import PricingDialog from "./pricing-dialog";
 
  export default async function Pricing({
    company_id,
    user,
  }: {
    company_id: any;
    user: any;
  }) {
    const store_id = process.env.store_id
    let product_id = process.env.PRODUCT_ID;
 
    if (!productId) {
      throw new Error("No product ID found");
    }
 
    const productVariants = await getProductVariants(product_id);
    
 
    return (
      <>
        <PricingDialog
          productVariants={productVariants}
          company_id={company_id}
          user={user}
          store_id={store_id}
        />
      </>
    );
  }

Imports

The first thing you notice is that we import two already created guides:

  1. getProductVariants - the function to retrieve the available variants for a product
  2. PricingDialog - rendering the pricing information and making it possible to create a checkout link
  import { getProductVariants } from "./variants";
  import PricingDialog from "./pricing-dialog";

Parameters

What you also notice, is that this function retrieves 50% of the available parameters in PricingDialog. We do this, as we are getting this information from the main page.tsx page. The reason is, we will use 'cookie based authentication' from Supabase and Next.js. That means that we will need to get the required backend data from our main page.

The remaining two are created during this Server component:

  1. productVariants
  2. store_id

The value for the store_id https://{store_id}.lemonsqueezy.com is retrieved from our .env file. In this file you can store your store_id, so that the Lemon Squeezy checkout link will be created for the correct webshop.

The productVariants requires a bit more explanation.

productVariants

  let product_id = process.env.PRODUCT_ID;
 
  if (!productId) {
    throw new Error("No product ID found");
  }
 
  const productVariants = await getProductVariants(product_id);

We retrieve the product_id from the .env file, just like we do with the store_id. However, we also do an additional check for the product id, because without this ID, we will not be able to render out the pricing dialog. After, we call the getProductVariants function using the product_id as input for the parameter.

What is important to note here, and this is why we can't use one component with the new Next.js 13 App Router, is that this function of Pricing.tsx is a Server Component. In a server component we are able to render out the function with await, because at the top we stated that this component is an async server component. We unfortunately, can't pass an await statement for a promise to a client component. Which is also the reason we will create two seperate ones.

Creating another component

Was creating an additional component really required? Probably not, as you would also be able to just create 3 pages (1 page, 2 components). However, with this setup you will need to do a lot of coding in the page.tsx file. Such as conditional statements, additional imports, generally cluttering the page. So for this part I opted to create a seperate 'Pricing' component, which also has two different components in and off itself.

Like what you see? Do you prefer to have a ready made app instead of building the integration yourself?

No worries, we have got you covered.

With Supaboost, you will be able to skip at least 30 days development time, by having these features readily available:

  • Auth
  • Lemon Squeezy integration
  • Safe development with Typescript
  • Next.js App Router
  • Supabase SQL scripts
  • And much more.

Get Supaboost

View

Next step

Click here to continue to Billing

View