DEV Community

Hidetaka Okamoto
Hidetaka Okamoto

Posted on • Originally published at wp-kyoto.net

Implementing Subscription Management with Next.js and Clerk Billing

Clerk has recently released Clerk Billing, a new feature that simplifies subscription management for web applications. This article will guide you through implementing Clerk Billing in a Next.js application and explain its basic usage.

Setting Up the Environment

Let's start by creating a new Next.js application:

npx create-next-app@latest nextjs-clerk-billing-app
Enter fullscreen mode Exit fullscreen mode

For this tutorial, we'll use the default settings. Just keep pressing Enter when prompted:

✓ Would you like to use TypeScript? … No / Yes
✓ Would you like to use ESLint? … No / Yes
✓ Would you like to use Tailwind CSS? … No / Yes
✓ Would you like your code inside a src/ directory? … No / Yes
✓ Would you like to use App Router? (recommended) … No / Yes
✓ Would you like to use Turbopack for next dev? … No / Yes
✓ Would you like to customize the import alias (@/* by default)? … No / Yes
Enter fullscreen mode Exit fullscreen mode

Setting Up the Clerk SDK

Image description

After creating your application, install the Clerk SDK. You can follow the instructions in the Clerk dashboard for guidance:

npm install @clerk/nextjs
Enter fullscreen mode Exit fullscreen mode

Setting Environment Variables

Create a .env file in your project root and set up your Clerk API keys. You can copy and paste this data from the tutorial in the dashboard:

NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_xxx
CLERK_SECRET_KEY=sk_test_xxx
Enter fullscreen mode Exit fullscreen mode

Configuring Middleware

Next, create a src/middleware.ts file to set up Clerk's middleware, which will provide the foundation for user authentication:

import { clerkMiddleware } from '@clerk/nextjs/server';
export default clerkMiddleware();
export const config = {
  matcher: [
    '/((?!_next|[^?]*\\.(?:html?|css|js(?!on)|jpe?g|webp|png|gif|svg|ttf|woff2?|ico|csv|docx?|xlsx?|zip|webmanifest)).*)',  
    '/(api|trpc)(.*)',
  ],
};
Enter fullscreen mode Exit fullscreen mode

Setting Up Clerk Billing

Clerk Billing needs to be enabled from the dashboard. You'll notice a new [Subscription (beta)] tab has been added. Click the [Get Started] button to proceed.

Image description

To use Clerk Billing, you'll need to register for a plan and migrate to Session JWT v2. For JWT v2, you can follow the instructions in the Changelog.

Image description

Setting Up Pricing Data

Clerk Billing allows you to configure subscription plan information through the Clerk dashboard.

Image description

There's a Free plan already available. Click [Add plan] to create a new plan, which you can delete later if needed.

Image description

Set up the plan name, slug, and description. When you enter the plan name, Clerk will automatically generate a slug using lowercase letters and underscores (_).

Image description

Next, configure the pricing. Currently, it appears that only USD subscriptions are supported. For the [Annual Discount], enter the monthly equivalent price after discount rather than the discount amount itself. For example, if you want to set a $4.98/month plan with an annual price of $48, enter 4 (because $48 ÷ 12 = $4). Additionally, if you turn off "Publicly available," the plan won't appear in Clerk-provided components.

Image description

While creating the pricing, you should also create a feature list.

Image description

Set the feature name and slug. The slug will be used in Clerk components.

Image description

After saving the features, save the entire plan to complete the addition.

Image description

Enabling Clerk Billing

Once all the preliminary setup is complete, the [Enable Billing] button will appear on your dashboard. Click it to activate Clerk Billing.

Image description

Activation is now complete. It looks like you can also bring your own Stripe account if desired.

Image description

Basic Usage of Clerk Billing

Displaying the Pricing Table

Displaying a pricing table on your homepage is surprisingly simple. Just use the PricingTable component:

import { PricingTable } from "@clerk/nextjs";
import Image from "next/image";

export default async function Home() {
  return (
    <main>
      <PricingTable />
    </main>
  );
}
Enter fullscreen mode Exit fullscreen mode

If you've registered two plans, they will be displayed like this. The features you registered will appear as a feature list in the pricing table.

Image description

Note that Clerk login is required to process payments. Therefore, it's advisable to place the PricingTable component on a page that is displayed when the user is logged in.

Image description

The payment form appears as a floating panel.

Image description

Once payment is complete, Clerk components like PricingTable will immediately reflect the changes.

Image description

Access Control

To control access to specific features based on subscriptions, the Protect component is useful:

import { PricingTable, Protect } from "@clerk/nextjs";
import Image from "next/image";

export default async function Home() {
  return (
    <main>
      <Protect
        feature="dashboard_access"
        fallback={<p>Sorry, you don't have dashboard Access.</p>}
      >
        <div>
          <h1>Protected</h1>
        </div>
      </Protect>
    </main>
  );
}
Enter fullscreen mode Exit fullscreen mode

With this configuration, only people who have subscribed to a plan with the specified feature slug will see the child elements.

Image description

Server-Side Control

You can implement feature restrictions not only on the client side but also in server-side processing such as APIs and SSR. This can also be used for API control, so the distinction between this and Protect may be a subject for further research.

import { PricingTable, Protect } from "@clerk/nextjs";
import { auth } from "@clerk/nextjs/server";
import Image from "next/image";

export default async function Home() {
  const { has } = await auth()
  const canAccessDashboard = has({ feature: "dashboard_access" })

  if (!canAccessDashboard) {
    return (
      <main>
        <p>Sorry, you don't have dashboard Access.</p>
      </main>
    )
  }

  return (
    <main>
      <PricingTable />
      <Protect
        feature="dashboard_access"
        fallback={<p>Sorry, you don't have dashboard Access.</p>}
      >
        <div>
          <h1>Protected</h1>
        </div>
      </Protect>
    </main>
  );
}
Enter fullscreen mode Exit fullscreen mode

Pricing

When using Clerk Billing, an additional fee of 0.7% is charged on top of the Stripe processing fee.

This additional fee applies only in production environments, but the benefit of significantly reduced implementation and maintenance effort makes it cost-effective in many cases.

Conclusion

By implementing Clerk Billing, you can easily display pricing tables and control access based on subscriptions. Since feature restrictions can be applied on both the client and server sides, flexible implementation is possible. Considering the effort required for implementation and operational costs, it's well worth the additional fee. This should bring significant benefits, especially for small teams and individual developers, by saving development time.

Top comments (1)

Collapse
 
nextgengk profile image
GAURAV KUMAR

Hello,

Currently, I’m trying to implement feature based limits on a user’s subscription plan (e.g., basic, intermediate, pro) using Clerk for authentication and Supabase for tracking usage.

In clerk billing like we have three plans, basic for all in which we can generate 5/account readme generation, pro has 50/month and premium has unlimited/year so how we can restrict??

So, how can i implement please you suggest some idea!!