We use cookies to enhance your experience on the site
CodeWorlds

after() API - Running code after the response

In the infrastructure of Metropolis Quantum 2150, where every operation must be optimized, you will learn about the

after()
API - a function that lets you run code after the response has been sent to the user. It is the ideal solution for tasks such as logging, analytics, or cleanup.

Problem: Blocking side effects

Imagine a typical scenario - a user visits a product page, and you want to:

  1. Return the product data (essential)
  2. Log the visit (side effect)
  3. Update statistics (side effect)
  4. Send an event to analytics (side effect)

Without

after()
, all of these operations block the response:

1// Bad approach - everything blocks the response
2export async function GET(request: Request) {
3  const product = await getProduct(id);
4
5  // These operations delay the response!
6  await logVisit(id);
7  await updateStats(id);
8  await sendAnalytics('product_view', { id });
9
10  return Response.json(product);
11}

Solution: after() API

after()
lets you schedule code to run AFTER the response is sent:

1import { after } from 'next/server';
2
3export async function GET(request: Request) {
4  const product = await getProduct(id);
5
6  // Schedule execution after the response
7  after(async () => {
8    await logVisit(id);
9    await updateStats(id);
10    await sendAnalytics('product_view', { id });
11  });
12
13  // Response is sent immediately!
14  return Response.json(product);
15}

Enabling the after() API

after()
requires enabling an experimental flag:

1// next.config.js
2module.exports = {
3  experimental: {
4    after: true,
5  },
6};

Usage in different contexts

In Route Handlers

1// app/api/orders/route.ts
2import { after } from 'next/server';
3import { sendEmail, updateInventory, notifyWarehouse } from '@/lib/services';
4
5export async function POST(request: Request) {
6  const orderData = await request.json();
7
8  // Essential operation - create the order
9  const order = await createOrder(orderData);
10
11  // Side effects - run after the response
12  after(async () => {
13    // Confirmation email
14    await sendEmail({
15      to: orderData.email,
16      subject: 'Order confirmation',
17      template: 'order-confirmation',
18      data: order,
19    });
20
21    // Update inventory
22    await updateInventory(order.items);
23
24    // Notify the warehouse
25    await notifyWarehouse(order);
26
27    // Audit log
28    await auditLog('order_created', { orderId: order.id });
29  });
30
31  // Immediate response
32  return Response.json({
33    success: true,
34    orderId: order.id
35  });
36}

W Server Components

1// app/products/[id]/page.tsx
2import { after } from 'next/server';
3import { trackPageView } from '@/lib/analytics';
4
5export default async function ProductPage({ params }: { params: Promise<{ id: string }> }) {
6  const product = await getProduct((await params).id);
7
8  // Tracking after the page renders
9  after(async () => {
10    await trackPageView({
11      page: 'product',
12      productId: (await params).id,
13      productName: product.name,
14      category: product.category,
15    });
16  });
17
18  return (
19    <div className="product-page">
20      <h1>{product.name}</h1>
21      <p>{product.description}</p>
22      <span className="price">${product.price}</span>
23    </div>
24  );
25}

W Server Actions

1// app/actions/checkout.ts
2'use server';
3
4import { after } from 'next/server';
5import { revalidatePath } from 'next/cache';
6
7export async function completeCheckout(formData: FormData) {
8  const cartId = formData.get('cartId') as string;
9
10  // Essential operation
11  const order = await processPayment(cartId);
12
13  if (!order.success) {
14    return { error: 'Payment failed' };
15  }
16
17  // Revalidate paths
18  revalidatePath('/cart');
19  revalidatePath('/orders');
20
21  // Side effects after the response
22  after(async () => {
23    // Clear the cart in the background
24    await clearCart(cartId);
25
26    // Generate PDF invoice
27    await generateInvoice(order.id);
28
29    // External integrations
30    await syncWithERP(order);
31    await notifyShipping(order);
32
33    // Update the loyalty program
34    await updateLoyaltyPoints(order.userId, order.total);
35  });
36
37  return { success: true, orderId: order.id };
38}

Multiple after() calls

You can use

after()
multiple times - all callbacks will run:

1import { after } from 'next/server';
2
3export async function POST(request: Request) {
4  const data = await request.json();
5  const result = await processData(data);
6
7  // Logging
8  after(async () => {
9    await logger.info('Data processed', { id: result.id });
10  });
11
12  // Analytics
13  after(async () => {
14    await analytics.track('data_processed', {
15      processingTime: result.duration,
16      dataSize: data.length,
17    });
18  });
19
20  // Cleanup
21  after(async () => {
22    await cleanupTempFiles(result.tempPath);
23  });
24
25  return Response.json(result);
26}

Error handling w after()

Errors inside

after()
do not affect the response, but should be handled:

1import { after } from 'next/server';
2
3export async function GET(request: Request) {
4  const data = await fetchData();
5
6  after(async () => {
7    try {
8      await riskyOperation();
9    } catch (error) {
10      // Log the error but do not interrupt
11      console.error('After callback failed:', error);
12      await errorReporting.capture(error);
13    }
14  });
15
16  return Response.json(data);
17}

Practical example - Notifications system

1// app/api/posts/[id]/like/route.ts
2import { after } from 'next/server';
3import { getSession } from '@/lib/auth';
4
5export async function POST(
6  request: Request,
7  { params }: { params: Promise<{ id: string }> }
8) {
9  const session = await getSession();
10  if (!session) {
11    return Response.json({ error: 'Unauthorized' }, { status: 401 });
12  }
13
14  // Essential operation - add the like
15  const like = await addLike((await params).id, session.userId);
16
17  // All notifications and side effects after the response
18  after(async () => {
19    const post = await getPost((await params).id);
20
21    // Notify the post author
22    if (post.authorId !== session.userId) {
23      await createNotification({
24        userId: post.authorId,
25        type: 'like',
26        message: `${session.user.name} liked your post`,
27        link: `/posts/${(await params).id}`,
28      });
29
30      // Push notification
31      await sendPushNotification(post.authorId, {
32        title: 'New like!',
33        body: `${session.user.name} liked your post`,
34      });
35    }
36
37    // Update statistics
38    await incrementPostStats((await params).id, 'likes');
39
40    // Update the feed algorithm
41    await updateFeedRanking((await params).id, 'engagement');
42  });
43
44  return Response.json({ liked: true, likeCount: like.count });
45}

When to use after()?

Ideal use cases:

  • Logging and auditing - saving user actions
  • Analytics - tracking events and metrics
  • Notifications - sending emails, push notifications
  • Cleanup - removing temporary files
  • Synchronization - updating external systems
  • Report generation - creating files in the background

Do not use for:

  • Validation - must happen before the response
  • Authorization - must happen before the response
  • Data needed in the response - obvious!
  • Operations that require confirmation - the user will not see the result

Summary

The

after()
API in Next.js is a powerful optimization tool:

  • Faster responses - side effects do not block the user
  • Better UX - the user sees the result immediately
  • Cleaner code - clear separation of essential work and side effects
  • Reliability - errors in after() do not break the response

In Metropolis Quantum 2150, where every millisecond matters,

after()
lets your applications run at the speed of light while side effects quietly execute in the background!

Go to CodeWorlds