NextJS 서버 액션(Server Actions)
서버 액션 실행 모델, 폼 흐름, useFormState/useFormStatus, 낙관적 업데이트와 제약사항 정리
API Route의 대체가 아니라, “요청-처리-UI”를 재구성하는 추상화
서버 액션을 처음 접하면 대부분 이렇게 이해한다.
“API Route를 더 간단하게 만든 기능”
이 이해는 절반만 맞고, 절반은 틀리다.
서버 액션은 API Route를 대체하는 것이 아니라,
UI 중심 애플리케이션에서 서버 요청을 다루는 방식을 바꾼 추상화다.
이 글은 서버 액션의 문법이 아니라,
어떤 문제를 해결하려고 등장했는지를 중심으로 설명한다.
1. 서버 액션의 실행 모델
“요청을 보내는 코드”가 아니라 “서버에서 실행되는 함수”
❌ 잘못된 이해
- 서버 액션 = API Route를 감춘 함수
- 클라이언트에서 호출되는 서버 함수
이 관점에서는 서버 액션의 설계 의도가 보이지 않는다.
✅ 올바른 이해
서버 액션은 다음 특징을 가진다.
- 항상 서버에서 실행
- 클라이언트는 “요청 트리거” 역할만 수행
- 실행 결과는 UI 렌더링 흐름으로 다시 합류
즉, 서버 액션은
요청 → 처리 → UI 반영을 하나의 React 흐름 안으로 끌어온다.
중요한 점:
- fetch를 직접 호출하지 않는다
- JSON 응답을 직접 파싱하지 않는다
- “네트워크 레이어”를 의식하지 않게 만든다
👉 서버 액션은 서버 로직을 UI 생명주기에 결합한다.
2. 폼 처리 흐름의 변화
기존 방식 vs 서버 액션
❌ 기존 React + API Route 흐름
- 폼 제출
- fetch 호출
- API Route 실행
- JSON 응답
- 클라이언트 상태 갱신
- UI 업데이트
문제:
- 네트워크 로직과 UI 로직이 분리
- 에러 처리 분산
- 상태 관리 복잡도 증가
✅ 서버 액션 기반 흐름
- 폼 제출
- 서버 액션 실행
- 서버에서 데이터 처리
- 캐시 무효화 / 재렌더링
- UI 자동 반영
핵심 변화는 이것이다.
“응답을 처리한다”가 아니라
“다시 렌더링한다”
서버 액션은
HTTP 응답을 UI 상태로 번역하는 단계를 제거한다.
3. useFormState / useFormStatus의 역할
“폼 UX를 서버 중심으로 재구성”
서버 액션은 비동기 요청이기 때문에
사용자 피드백이 반드시 필요하다.
이를 위해 등장한 것이 두 훅이다.
useFormStatus
현재 폼 제출 상태를 알려주는 훅
- pending 여부
- 제출 중 UI 제어
정신 모델:
“지금 서버 액션이 실행 중인가?”
이 훅은
- 전역 상태 ❌
- 로컬 UI 상태 ⭕
로 설계되었다.
useFormState
서버 액션의 결과를 UI로 전달
- 서버에서 반환한 값 수신
- 유효성 에러, 메시지 처리
중요한 점:
- 서버 액션의 반환값은 UI의 일부
- 별도 API 응답 처리 로직 불필요
👉 이 두 훅은
폼 상태를 클라이언트 상태가 아니라 ‘서버 실행 결과’로 관리하게 만든다.
4. Optimistic Update
“응답을 기다리지 않고, 결과를 가정한다”
서버 액션은 서버에서 실행되기 때문에
기본적으로는 응답 후 UI 반영 구조다.
하지만 UX 상 즉각적인 반응이 필요한 경우가 있다.
여기서 등장하는 개념이 Optimistic Update다.
Optimistic Update의 정신 모델
“이 요청은 성공할 가능성이 높다”
→ UI를 먼저 바꾼다
- 사용자 입력 즉시 반영
- 서버 실패 시 롤백
서버 액션과 결합되면:
- 낙관적 UI
- 서버 액션 실행
- 캐시 재검증으로 최종 동기화
👉 중요한 점은
낙관적 업데이트는 서버 액션을 대체하지 않는다.
서버 액션은 여전히 단일 진실 소스다.
5. 서버 액션의 제약과 한계
반드시 알고 써야 하는 부분
서버 액션은 만능이 아니다.
구조적 제약
- 항상 서버에서 실행
- 브라우저 API 접근 불가
- 장시간 실행 작업에 부적합
설계적 제약
- 범용 API 엔드포인트로 사용 ❌
- 외부 클라이언트 접근 ❌
- 모바일/외부 서비스용 API ❌
👉 서버 액션은
NextJS 앱 내부 UI 요청 전용 추상화다.
흔한 오해에서 오는 안티패턴
- 서버 액션을 REST API처럼 설계
- 모든 요청을 서버 액션으로 몰아넣기
- 에러 처리를 클라이언트 상태로 분리
- optimistic update를 기본값으로 사용
이 패턴들은
서버 액션의 장점을 스스로 제거한다.
최종 정리: 서버 액션 사고 체크리스트
- 이 요청은 UI에서 직접 발생하는가?
- 외부 클라이언트가 이 엔드포인트를 호출해야 하는가?
- 응답을 “처리”할 필요가 있는가, “렌더링”하면 되는가?
- 이 로직은 서버에서 실행되어야 안전한가?
- 캐시 무효화 흐름과 자연스럽게 연결되는가?
결론: 서버 액션은 “서버 호출”이 아니라 “UI 흐름의 일부”다
서버 액션은
API Route를 없애기 위한 기능이 아니다.
- 요청
- 처리
- 캐시
- UI 반영
이 네 단계를
하나의 React 렌더링 사이클로 묶기 위한 추상화다.
서버 액션을 잘 쓴다는 것은
서버 코드를 줄이는 것이 아니라,
UI와 서버 사이의 경계를 명확히 그리는 것이다.
