javascript 48 lines · 8 steps

Deferring work with after() in Next.js

A route handler validates input, creates a subscriber, then sends a welcome email after the response ships.

Explained by highlit
1import { after } from "next/server";
2import { NextResponse } from "next/server";
3import { z } from "zod";
4import { resend } from "@/lib/resend";
5import { db } from "@/lib/db";
6 
7const schema = z.object({
8 email: z.string().email(),
9 name: z.string().min(1),
10});
11 
12export async function POST(request) {
13 const body = await request.json();
14 const parsed = schema.safeParse(body);
15 
16 if (!parsed.success) {
17 return NextResponse.json(
18 { error: parsed.error.flatten().fieldErrors },
19 { status: 422 }
20 );
21 }
22 
23 const { email, name } = parsed.data;
24 
25 const subscriber = await db.subscriber.create({
26 data: { email, name },
27 });
28 
29 after(async () => {
30 try {
31 await resend.emails.send({
32 from: "Acme <welcome@acme.dev>",
33 to: email,
34 subject: `Welcome aboard, ${name}!`,
35 react: WelcomeEmail({ name }),
36 });
37 
38 await db.subscriber.update({
39 where: { id: subscriber.id },
40 data: { welcomedAt: new Date() },
41 });
42 } catch (err) {
43 console.error("Failed to send welcome email", err);
44 }
45 });
46 
47 return NextResponse.json({ id: subscriber.id }, { status: 201 });
48}
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1Validate request bodies at the boundary and return a structured 422 before touching your database.
  2. 2Next.js's after() lets you run non-critical work once the response is already sent, keeping the request fast.
  3. 3Isolate deferred side effects with their own try/catch so a failed email never breaks the successful signup.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Deferring work with after() in Next.js — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code