클라이언트에서 부르지만 서버에서 실행돼
서버 액션은 서버에서 실행되는 async 함수야. 클라이언트 컴포넌트에서는 일반 함수처럼 참조하지만, Next.js가 뒤에서 고유한 POST 엔드포인트와 연결해 줘. 내부 변경 작업을 위해 URL과 JSON 배관을 따로 만들지 않아도 되는 이유야.
선언 방식은 두 가지야
| 방식 | 선언법 |
|---|---|
| 파일 단위 | 파일 첫 줄에 'use server'를 두면 그 파일의 모든 내보내기가 액션이 돼. |
| 함수 단위 | 서버 컴포넌트 안의 비동기 함수 본문 첫 줄에 'use server'를 둬. |
내부 CRUD의 반복 배관을 없애
/api/.../route.ts를 만들고, 클라이언트에서 fetch()하고, 양쪽에서 JSON을 해석하는 흐름을 한 함수로 줄여. CSRF 방어, 암호화된 액션 ID, 쓰이지 않는 액션의 빌드 제외도 프레임워크가 제공해.
공개 HTTP 계약은 대신하지 않아
외부 서비스가 호출하는 API, webhook, 장기적으로 안정된 URL이 필요한 연동은 라우트 핸들러의 책임이야. 서버 액션은 앱 내부 UI가 서버 변경을 부르는 경계로 써.
변경 함수를 만들 때 입력 검증, 세션 확인, 권한 검사, DB 쓰기, 캐시 무효화의 순서를 한곳에서 읽을 수 있게 해. UI가 여러 곳이어도 같은 도메인 변경을 공유하도록 액션을 별도 서버 파일에 두고, 반환 상태만 폼마다 필요한 모양으로 어댑트해. 실패한 쓰기 뒤에는 무효화가 실행되지 않아야 해.
서버 액션이 함수처럼 보인다고 로컬 함수는 아니야. 네트워크를 건너는 POST이고 중복 제출·지연·실패가 생길 수 있어. 한 번만 실행된다고 가정하지 말고 idempotency가 필요한 결제나 주문에는 요청 키와 DB 제약을 함께 둬.
같은 내부 변경을 라우트 핸들러+fetch와 서버 액션으로 각각 만들어 요청·직렬화·오류 코드 양을 비교해. 미사용 액션이 build에서 빠지는지, 액션이 POST로만 도달하는지 확인하고 외부 curl 소비자가 필요해지는 순간 어느 쪽이 맞는지도 설명해. 액션 이름은 saveData보다 publishPost, transferBalance처럼 도메인 결과를 말하게 지어. HTTP URL이 사라진 만큼 함수 이름과 타입이 변경 계약을 설명하는 주된 표면이 되기 때문이야.