How to setup a waitlist using resend & ZippyStarter
Morgan Feeney
4 min read
Learn how to quickly setup a simple waitlist using shadcn, nextjs, ZippyStarter, and Resend
I wanted to validate an idea I had for a potential product, something directly related to ZippyStarter. I’ve seen plenty of people on X recommending waitlists as a good way to test demand for products and services so decided to create one.
I hadn’t created a waitlist before, and wasn’t into researching using an all-in-one waitlist product such as Launchlist, so, partly out of curiosity and out of frugality built my own waitlist using ZippyStarter and a product called Resend.
ZippyStarter is built on Nextjs and shadcn, Resend has docs on how to integrate with Nextjs.
The UI
I wanted to invoke a modal that contained a form that took a name and email address. Nothing fancy, but because ZippyStarter builds on top of shadcn it was extremely quick to set up, and for the theming to be applied automatically.
Desired Behaviour
- When the form submits a name and email address are posted to a database.
- Feedback is displayed to the subscriber.
- An email confirmation is then sent to the subscriber.
- I should be able to view entries in the database via a GUI.
Backend
I initially thought that using one of Vercel’s database SDK would be enough, so tried out Vercel Postgres. It didn’t take long to get up and running but I still needed to send a confirmation email and didn’t want to have to set that up myself; so started looking for an alternative that included it.
Resend
I eventually found Resend. Their docs are quite good, there’s plenty of example code, and code samples for a multitude of languages, and it’s easy to connect to their service.
Here's some of their example code:
import { EmailTemplate } from '@/components/email-template';
import { Resend } from 'resend';
const resend = new Resend(process.env.RESEND_API_KEY);
export async function POST() {
const { data, error } = await resend.emails.send({
from: 'onboarding@resend.dev',
to: 'delivered@resend.dev',
subject: 'Hello world',
react: EmailTemplate({ firstName: 'John' }),
});
if (error) {
return Response.json({ error });
}
return Response.json(data);
}
If you look at the highlighted lines, you'll notice that a template is imported and then used to render the email content, passing in a variable for firstName
.
You can set this up by defining the template yourself, like so:
import * as React from 'react';
interface EmailTemplateProps {
firstName: string;
}
export const EmailTemplate: React.FC<Readonly<EmailTemplateProps>> = ({
firstName,
}) => (
<div>
<h1>Welcome, {firstName}!</h1>
</div>
);
With a few tweaks the code was updated to accept variables for the name and email that get submitted by the waitlist form.
export async function POST(request: Request) {
const { searchParams } = new URL(request.url);
const name = searchParams.get("name") ?? "";
const email = searchParams.get("email") ?? "";
const { data, error } = await resend.emails.send({
from: 'onboarding@resend.dev',
to: 'delivered@resend.dev',
subject: 'Hello world',
react: EmailTemplate({ name, email }),
});
if (error) {
return Response.json({ error });
}
return Response.json(data);
}
Once you connect to the backend of Resend you can see emails being sent like this:
Conclusion
I'm glad I found Resend as I believe it saved me many hours faffing around looking for various integrations, and then working them into my code.
The drawback with building your own waitlist from scratch is that with each step you could be opening a new can of worms. With Resend, formatting HTML for emails is one such example.
Their docs link straight to another of their products React Email, and it’s a rabbit hole in itself.
I was extremely low on time and needed to get my waitlist out there super-quick, and didn’t want to spend further time learning specifics for yet another npm package. As a result I completely swerved it and just went with a quick and bare-bones bit of HTML, I didn't even style it.
I would advise against doing anything this bare-bones, getting people onto a waitlist is an opportunity to start building an experience in itself, and to create anticipation and further reinforce your brand.