TechFeedTechFeed
Frontend

after, waitUntil, 응답 후 작업, 페이지뷰 | 문의 저장이 끝났는데 버튼이 안 풀리면?

문의 저장이 끝났는데 버튼이 안 풀리면 액션이 메일을 기다린 겁니다. Next.js after는 응답을 보낸 뒤에 로그와 페이지뷰를 돌리고, 버셀은 15.1부터 대기 유틸 대신 이 함수를 권합니다. 정적 페이지에서는 빌드 때 돕니다. 프론트엔드, React, 서버 액션, API, 개발자, 백엔드, 넥스트 기준으로 응답 뒤 칸만 보고 폼 훅 글, 캐시 헤더 글과 자리를 섞지 않습니다. 2026년 8월 넥스트, 버셀 공식 문서.

by

문의 버튼을 눌렀는데 저장은 끝났는데도 화면이 한동안 안 바뀐 적 있으신가요? 액션이 메일을 기다리면 버튼이 잠긴 채로 남습니다. 응답을 먼저 보내고, 로그와 메일은 after에 넣습니다. 저장 성공만 바로 돌려주면 버튼이 풀립니다. 넥스트 15.1부터 안정이고, 버셀은 15.1 이상에서 대기 유틸 대신 이 함수를 쓰라고 적습니다. 정적 페이지에서 부르면 빌드 때 돕니다. 저는 12개 사이트 페이지뷰와 파트너십 문의를 이 칸으로 나눕니다. 버튼 잠금은 폼 훅 글, 로컬 메일은 메일핏 글입니다. 여기는 응답이 나간 뒤 칸만 봅니다.


기준일은 2026년 8월 넥스트 after 문서와 버셀 함수 패키지 문서입니다.


저장은 끝났는데 화면이 안 바뀌면 어디를 보나

액션이 메일이나 로그를 끝까지 기다리면, 버튼은 그 시간만큼 잠깁니다. 사용자에게 돌려줄 값만 먼저 보내고, 나머지는 응답 뒤에 돌립니다.


파트너십 문의를 슈퍼베이스에 넣은 뒤, 같은 함수에서 리센드를 await 한 날이 있습니다. 저장은 이미 끝났는데 화면은 대기가 안 풀렸습니다. 수신함이 느리면 버튼이 같이 느려집니다. 폼 훅 글은 제출 중 잠금입니다. 오늘은 그 잠금이 길어지는 이유, 서버가 메일을 응답 앞에 둔 칸입니다.


언제 도나버튼·화면잘 맞는 자리
메일·로그를 await응답 전벤더가 느리면 같이 멈춤실패를 화면에 바로 보여 줄 때
프라미스만 띄움서버가 끊기면 중간에 죽음화면은 빨라 보임로컬 노드만, 서버리스는 비추천
after응답 또는 사전 렌더가 끝난 뒤화면은 먼저 나감페이지뷰, 로그, 가입 메일
대기 유틸함수 수명을 프라미스만큼 연장화면은 먼저 나감넥스트 15.1 미만, 버셀 일반 함수

캐시 헤더 칸은 캐시 컨트롤 글입니다. 쿠키 속성은 세임사이트 글입니다. 서버 액션 보안은 서버 액션 글입니다. 오늘은 응답이 나간 뒤 한 줄만 봅니다.


사용자에게 보여줄 일은 after에 넣지 않습니다 | 에러를 화면에 돌려줘야 하면 await가 맞습니다. 로그와 통계, 가입 메일처럼 화면과 상관없는 일만 뒤로 밉니다.


응답을 보낸 뒤에 로그를 거는 순서

서버에서 after를 부르고, 콜백에 로그를 넣습니다. 넥스트 15.1부터 안정이고, 서버 컴포넌트와 서버 액션, 라우트 핸들러, 프록시에서 쓸 수 있습니다.


공식 예는 레이아웃에서 렌더가 끝난 뒤 로그 함수를 한 번 호출합니다. 요청 시점 에이피아이가 아니라서, 이 함수만 불렀다고 라우트가 동적으로 바뀌지는 않습니다. 정적 페이지면 빌드 때, 또는 재검증 때 콜백이 돕니다. 페이지뷰처럼 방문자마다 남겨야 하는 일은 정적 페이지 루트가 아니라, 이미 동적인 액션이나 라우트에 둡니다.


저는 페이지뷰를 라우트에서 await 했다가 본문이 느려진 적이 있습니다. 슈퍼베이스 삽입이 응답을 붙잡고 있었습니다. 지금은 저장 결과만 돌려주고, 삽입은 콜백으로 옮기는 쪽으로 맞춥니다. 문의 봇 칸은 턴스타일 글입니다. 검증은 응답 앞에서 끝냅니다. 로그는 그 뒤입니다.


서버 액션 | 문의 저장 후 메일만 뒤로
import { after } from 'next/server' export async function submitPartnership(formData) { const row = await saveInquiry(formData) after(async () => { await sendAckMail(row.id) }) return { ok: true, id: row.id } }
레이아웃 | 렌더가 끝난 뒤 로그
import { after } from 'next/server' import { log } from '@/app/utils' export default function Layout({ children }) { after(() => { log() }) return children }
메일 await와 떠 있는 프라미스와 after를 비교한 세 칸 표
화면이 기다려야 하면 await, 로그와 메일은 응답 뒤 after입니다

사실 after를 썼다고 정적 페이지가 동적으로 바뀌지는 않는다

문서는 요청 시점 에이피아이가 아니라고 적습니다. 정적 페이지에서 부르면 콜백은 빌드 때, 또는 재검증 때 돕니다.


방문자마다 페이지뷰를 남기려고 정적 글 페이지에 이 함수만 넣으면, 빌드 한 번에 한 줄만 남고 실제 조회는 비어 있을 수 있습니다. 조회는 이미 동적인 라우트나 액션, 또는 클라이언트에서 부르는 페이지뷰 주소로 둡니다. 이 사이트의 페이지뷰는 브라우저가 에이피아이를 칩니다. 본문 에치티엠엘을 그 삽입이 붙잡지 않습니다.


에러가 나거나 낫파운드, 리다이렉트를 호출해도 콜백은 실행됩니다. 실패한 요청의 로그를 남기려면 오히려 맞습니다. 성공한 저장만 메일을 보내려면, 콜백 안에서 성공 여부를 보고 건너뜁니다. 중첩 호출도 됩니다. 유틸이 이 함수를 감싸도 됩니다.


정적 내보내기에서는 이 함수가 없습니다 | 공식 표는 노드 서버와 도커는 되고, 정적 내보내기는 안 된다고 적습니다. 어댑터는 플랫폼마다 다릅니다. 프리빌트 에이치티엠엘만 올리는 칸과 함수가 있는 칸을 갈라 봅니다.


떠 있는 프라미스와 대기 유틸과 after가 다른 점

서버리스는 응답을 보내는 순간 실행을 거둘 수 있습니다. await 없이 띄운 삽입은 중간에 끊깁니다. 버셀은 넥스트 15.1부터 대기 유틸 대신 after를 쓰라고 적습니다.


대기 유틸은 버셀 함수 패키지의 waitUntil입니다. 프라미스가 끝날 때까지 함수 수명을 늘립니다. 넥스트가 아닌 함수, 또는 15.1 미만에서 같은 일을 할 때 씁니다. 넥스트 앱 라우터면 이 패키지를 또 깔 필요가 없습니다. 공식 본문이 그 순서를 적어 두었습니다.


둘 다 함수 최대 실행 시간 안에서만 돕니다. 한도가 끝나면 콜백도 잘립니다. 라우트에 최대 실행 시간을 초로 적을 수 있습니다. 문서 예는 5초입니다. 가입 메일이 자주 잘리면 초를 늘리거나, 메일 전용 큐로 넘깁니다. 로컬에서 실주소로 안 나가게 하는 칸은 메일핏 글입니다. 디엔에스 정렬은 디킴 글입니다.


버셀 일반 함수 | 넥스트 15.1 미만일 때
import { waitUntil } from '@vercel/functions' export async function POST() { waitUntil(logPageview()) return Response.json({ ok: true }) }
라우트 | 콜백이 잘리면 초를 늘린다
export const maxDuration = 30
정적 글 페이지와 서버 액션에서 after가 도는 시점을 나눈 비교
정적 페이지면 빌드 때 돌고, 방문자 로그는 동적 라우트에 둡니다

서버 컴포넌트 안에서 쿠키를 읽으면 런타임 에러가 난다

라우트와 서버 액션의 콜백 안에서는 쿠키와 헤더를 바로 읽습니다. 페이지와 레이아웃의 콜백 안에서는 읽지 않습니다. 렌더가 끝난 뒤에는 요청 트리를 모르기 때문입니다.


문서는 서버 컴포넌트에서 콜백 안에 쿠키를 두면 런타임 에러라고 적습니다. 렌더 중에 읽고, 그 값을 클로저로 넘깁니다. 부분 사전 렌더를 쓰는 페이지는 쿠키를 읽는 조각을 서스펜스로 감싼 뒤, 그 조각에서 값을 읽어 콜백에 넣습니다.


리액트 캐시로 콜백 안 함수를 합칠 수 있습니다. 같은 요청에서 로그를 두 번 넣지 않으려면 그 칸입니다. 플레이라이트로 버튼을 두 번 눌러 보는 순서는 플레이라이트 글입니다. 화면이 먼저 바뀌는지만 보면 되고, 메일 도착은 메일핏 화면에서 봅니다.


페이지 | 쿠키는 렌더 때 읽고 콜백에 넘긴다
import { after } from 'next/server' import { cookies, headers } from 'next/headers' export default async function Page() { const agent = (await headers()).get('user-agent') || 'unknown' const session = (await cookies()).get('session-id')?.value || 'anon' after(() => { logUserAction({ session, agent }) }) return null }

페이지 콜백 안에서 cookies()를 부르면 에러입니다 | 값은 렌더 중에 읽습니다. 라우트와 서버 액션만 콜백 안에서 바로 읽습니다.


오늘 15분에 페이지뷰 한 줄을 옮기는 순서

동적 라우트나 액션에서 응답을 먼저 주고, 삽입은 콜백으로 옮기면 됩니다. 정적 글 페이지에 방문자 로그를 넣지 않습니다.


  1. 넥스트가 15.1 이상인지 패키지 파일에서 봅니다. 미만이면 대기 유틸이거나, 먼저 올립니다.
  2. 사용자에게 돌려줄 저장만 await로 남깁니다. 메일과 페이지뷰와 인덱스나우 핑은 콜백으로 옮깁니다.
  3. 페이지나 레이아웃이면 쿠키와 헤더를 렌더 중에 읽고 넘깁니다. 라우트면 콜백 안에서 읽어도 됩니다.
  4. 로컬에서는 메일핏 1025로 넣고, 8025에서 제목이 남는지 봅니다. 실주소 키는 로컬 파일에서 뺍니다.
  5. 버셀 로그에서 콜백 에러가 응답 코드와 따로 찍히는지 봅니다. 한도에 걸리면 최대 실행 시간을 초로 늘립니다.
  6. 자기 호스팅이면 종료 신호 뒤에 콜백이 끝나도록 10초에서 30초 여유를 둡니다. 문서는 그 구간을 권합니다.

시크릿이 커밋에 붙는 칸은 시크릿 체크 글입니다. 네이버에 주소를 넘기는 핑은 응답을 막지 않게 콜백이나 별도 스크립트에 둡니다. 본문 에치티엠엘과 검색 핑을 한 await에 묶지 않습니다.


페이지뷰 한 줄을 after 콜백으로 옮기는 여섯 단계 순서
오늘 순서는 저장 결과 먼저, 로그와 메일은 그 다음입니다

참고 자료


내부 연계: 폼 이중 제출, 메일핏, 캐시 컨트롤, 서버 액션, 세임사이트, 플레이라이트


자주 묻는 질문

await 없이 fetch만 호출하면 안 되나?

로컬 노드 프로세스면 살아 남을 수 있습니다. 버셀 같은 서버리스는 응답을 보내는 순간 실행을 거둡니다. 삽입이 중간에 끊기고, 로그가 비는 날이 있습니다. after나 대기 유틸이 그 수명을 한도 안에서 늘립니다. 화면에 실패를 보여 줘야 하면 그냥 await가 맞습니다.


정적 글 페이지에 페이지뷰를 넣어도 되나?

그 루트가 정적이면 콜백은 빌드 때나 재검증 때 돕니다. 방문자마다 한 줄이 남지 않습니다. 조회는 동적 라우트나 브라우저가 치는 에이피아이에 둡니다. 이 사이트도 본문을 기다리지 않고 페이지뷰 주소만 칩니다.


리다이렉트해도 메일이 나가나?

문서는 실패와 낫파운드, 리다이렉트여도 콜백이 실행된다고 적습니다. 성공한 저장만 보내려면 콜백 안에서 상태를 보고 건너뜁니다. 액션이 에러를 던지기 전에 아이디를 넘겨 두면, 실패 로그와 성공 메일을 가를 수 있습니다.


자기 서버 next start에서도 같나?

문서는 next start에서 된다고 적습니다. 종료할 때 인터럽트나 종료 신호를 보내고 기다리면, 떠 있는 요청과 콜백을 끝냅니다. 끄는 여유는 10초에서 30초를 권합니다. 정적 내보내기만 올리는 구성은 이 함수가 없습니다.


대기 유틸을 같이 써도 되나?

넥스트 15.1 이상이면 after만 씁니다. 버셀 문서가 그 순서를 권합니다. 같은 일에 둘을 겹치면 수명만 두 번 늘고, 읽기만 어려워집니다. 넥스트가 아닌 함수 파일만 대기 유틸을 둡니다.


콜백이 자주 잘리면?

함수 한도가 먼저 끝납니다. 라우트에 최대 실행 시간을 초로 늘리고, 그래도 메일 벤더가 느리면 큐로 넘깁니다. 로그가 비는 안내도 한도가 원인일 수 있다고 적습니다. 로컬 시험은 한도와 별개로 메일핏 화면만 보면 됩니다.


afterwaitUntil응답 후 작업페이지뷰Next.jsReact프론트엔드서버 액션API개발자백엔드버셀로그

관련 도구

함께 보면 좋은 문제 해결

EXPLORE / Frontend

이어서 읽어보기

전체 토픽 둘러보기