By Kevin Hou
4 minute read
Shipping a waitlist for a new feature can be a painful last mile to a developer's momentum. Using a mix of old and new tools, I was able to go from 0 to production in around an hour! DX has been on a rocketship this past year 🚀
Here's 5 free tools you can use to set up your next waitlist system:
Serverless Postgres has caused a stir recently and for a non-intensive access pattern like a waitlist it's an easy decision. They offer a generous free tier (3 GiB of data and 1 GB of RAM) which is more than enough for my use case.
The only downside is the “cold start” but it won't make or break our user's experience.
I initialized a new table gpt_4_waitlist
and within seconds I had a Postgres URL to get up and running. They also ship you a convenient NeonDB npm package that we'll use later.
Using @ codeiumdev I asked it to create a waitlist table for my newly created Neon DB:
Create a new postgres 16 table called
gpt_4_waitlist
that has the following columns:
- waitlist_id: string primary key auto generated
- email: string required unique
- ...
A few seconds later I had a query that executed perfectly. I used Neon's console GUI to check my schema and everything looks good. Database provisioned!
The great news with NextJS is that we don't need to setup a new project, manage CORS, or spin up a new server! Instead, we can use a server side endpoint file in our app/
directory. We use the following code to store our values in our NeonDatabase.
This took me about 5 minutes to setup. A very different story if I were to have made a new Flask/FastAPI Python server and deployed a new Kubernetes service.
1import { neon } from "@neondatabase/serverless";
2
3const sql = neon(process.env.WAITLIST_DATABASE_URL);
4
5export async function POST(req: NextRequest) {
6 const reqBody = await req.json();
7 await sql`INSERT INTO
8 gpt_4_waitlist (email, additional_details, occupation, years_of_experience, ...)
9 VALUES (
10 ${reqBody.email},
11 ${reqBody.additional_details},
12 ...
13 ) RETURNING *`;
14}
15
The last thing to do is to make a form that can send a payload to our endpoint. I've used yup
in the past for schema validation but zod
seems like the new kid on the block and I really like how simple their setup is.
It also plays really nicely with react-hook-form
, a headless form hook that manages your validation, error states, controlled inputs, etc. It let's you bring your own UI components so you can have maximum flexibility while keeping the setup cost for state management low.
1const generateFormSchema = z.object({ 2 email: z.string().min(1), 3 occupation: z.string().min(1), 4 // ... 5}); 6type GenerateFormValues = z.infer<typeof generateFormSchema>; 7 8export const WaitlistForm = () => { 9 const { handleSubmit, errors } = useForm<GenerateFormValues>({ 10 resolver: zodResolver(generateFormSchema), 11 mode: 'onChange', 12 // You can set default values if you'd like controlled components. 13 defaultValues: { ... } 14 }); 15 16 return ( 17 <form onSubmit={handleSubmit(onSubmit)}> 18 <label htmlFor="additionalDetails" className="mb-1 block leading-5"> 19 Additional Details 20 </label> 21 <textarea {...register('additionalDetails', { required: true })} /> 22 {errors.additionalDetails && ( 23 <p className="text-sm text-red">{errors.additionalDetails.message}</p> 24 )} 25 ... 26 </form> 27 ) 28} 29
As someone who holds their products to a high level of UX polish, I'm also a big advocate for tools that can make mundane tasks more delightful. I've been discovering, rediscovering, and tinkering on my own Postgres clients since 2016. I've finally arrived at my favorites:
Just like that, we have a live waitlist! Follow for more developer productivity tips and tools
If you're interested, here's my finished product: https://codeium.com/waitlist/gpt-4