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
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1Validate request bodies at the boundary and return a structured 422 before touching your database.
- 2Next.js's after() lets you run non-critical work once the response is already sent, keeping the request fast.
- 3Isolate deferred side effects with their own try/catch so a failed email never breaks the successful signup.
Related explainers
php
<?php namespace App\Services\Checkout;
Validating coupons with Laravel's Pipeline
pipeline
chain of responsibility
transactions
Intermediate
7 steps
javascript
function evaluate(expression) { const tokens = tokenize(expression); let pos = 0;
Building a recursive descent calculator
parsing
recursion
operator-precedence
Intermediate
8 steps
php
<?php namespace App\Services;
How a password strength validator works in PHP
validation
regular-expressions
data-driven
Intermediate
8 steps
javascript
import { useState, useEffect, useCallback, useRef } from 'react'; const cache = new Map(); const inflight = new Map();
Building a stale-while-revalidate hook in React
caching
request-deduplication
custom-hooks
Advanced
10 steps
rust
use chrono::{Duration, NaiveDate}; #[derive(Debug)] pub struct DateRange {
Parsing and iterating date ranges in Rust
error-handling
iterators
parsing
Intermediate
7 steps
javascript
import { useEffect, useRef, useState } from 'react'; export function useDelayedFlag(active, delay = 300) { const [visible, setVisible] = useState(false);
Delaying a loading spinner with a React hook
custom-hooks
debouncing
cleanup
Intermediate
8 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/deferring-work-with-after-in-next-js-explained-javascript-7267/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.