Table of contents
Introduction
Hey guys! In this blog post, we will implement a subscription model using LemonSqueezy in our Next.js app with the latest App router. If you're interested in learning about it, this is the post for you.
Getting Started
Let me tell you what I am going to cover in this blog post. First, we are going to bootstrap our Next.js project. Then we will set up our LemonSqueezy account. After that, we will learn how the subscription process works and how we are going to integrate LemonSqueezy subscriptions into our Next.js app. Then we will write code and finally deploy our app on Vercel. So we will cover everything from start to finish. This blog post expects you to have familiarity with React and Next.js (App router). If you know the basics you are good to go.
What we will be building today? We are going to build a simple app that will let the user create an account and subscribe to our product. Later he can cancel it anytime, change credit card credentials, and all that. So that’s the overview of what we are going to build.
Setup Next.js app
For this tutorial, I have created a [GitHub repo
](https://github.com/developeratul/lemonsqueezy-nextjs) that has a branch called starter
You will have to follow a simple GitHub workflow and checkout to this branch to get the starter code to follow along with this tutorial. The final code will be in the main
branch.
User Registration
Let’s create a very simple authentication where users can register and log in. No session management and all that other authorization stuff since that’s not the main purpose of this tutorial.
Let’s make some edits in the app/sign-up/page.tsx
"use client";
import Link from "next/link";
import { useRouter } from "next/navigation";
import React from "react";
import { toast } from "react-hot-toast";
import { Button } from "~/components/ui/button";
import { Input } from "~/components/ui/input";
import { axios } from "~/lib/axios";
import { useAuth } from "~/providers/auth";
import { SignUpResponse } from "../api/auth/sign-up/route";
export default function SignUp() {
const [input, setInput] = React.useState({ email: "", password: "" });
const { setUser, user } = useAuth();
const router = useRouter();
const handleInputChange: React.ChangeEventHandler<HTMLInputElement> = ({
target: { value, name },
}) => {
setInput((pre) => ({ ...pre, [name]: value }));
};
const handleSubmit: React.FormEventHandler<HTMLFormElement> = async (e) => {
try {
e.preventDefault();
const { email, password } = input;
if (!email || !password) return;
const { user, message } = await axios.post<any, SignUpResponse>("/api/auth/sign-up", {
email,
password,
});
setUser(user);
router.push("/");
toast.success(message);
} catch (err) {
//
}
};
return (
<div className="flex flex-col justify-center items-center gap-8 w-full">
<div className="w-full max-w-md bg-white/5 p-8 rounded-lg border border-gray-900">
<form onSubmit={handleSubmit} className="flex flex-col justify-center items-center gap-4">
<h2 className="text-2xl">Sign up</h2>
<Input
required
type="email"
onChange={handleInputChange}
name="email"
placeholder="Enter email"
/>
<Input
required
type="password"
placeholder="Enter password"
onChange={handleInputChange}
name="password"
/>
<Button type="submit" className="w-full">
Sign up
</Button>
</form>
</div>
<div>
<p>
Already have an account?{" "}
<Link className="text-blue-300 hover:underline underline-offset-4" href="/login">
Login
</Link>
</p>
</div>
</div>
);
}