Q&A

Next.js 14에서 서버 컴포넌트 에러 해결 방법

상욱

2일 전

7201

Next.js 14 App Router를 사용하는데 서버 컴포넌트에서 다음과 같은 에러가 발생합니다:

Error: async/await is not yet supported in Client Components

서버 컴포넌트로 설정했는데도 이런 에러가 나는 이유가 뭔가요? 어떻게 해결해야 하나요?

댓글 1

관리자2일 전

왜 발생하는 오류인가요?

Next.js 14 App Router에서 Server ComponentClient Component는 파일 단위로 구분됩니다.

  • 파일 최상단에 “use client” 가 있으면 Client Component로 간주됩니다.

  • 그렇지 않으면 기본적으로 Server Component가 됩니다.

async/awaitServer Component에서는 자유롭게 사용할 수 있지만, Client Component에서는 아직 지원되지 않으므로 다음과 같은 에러가 뜹니다.

Error: async/await is not yet supported in Client Components

주요 원인

  1. 현재 파일(또는 그 파일이 import 하는 하위 컴포넌트) 에 “use client” 가 선언돼 있는 경우.

  2. await 를 사용하는 함수가 Client Component 내부(예: useEffect 안)에서 직접 호출된 경우.

  3. next/dynamic 으로 ssr: false 로 로드한 컴포넌트가 내부에서 async 로 구현돼 있는 경우.

해결 방법

1️⃣ 파일이 Server Component인지 확인

// src/app/dashboard/page.tsx   ← Server Component (default)
export default async function DashboardPage() {
  const data = await fetchData();   // ✅ 정상
  return <div>{JSON.stringify(data)}</div>;
}

반대로 Client Component 로 만들고 싶다면 최상단에 “use client” 를 명시합니다.

// src/app/dashboard/ClientWidget.tsx
"use client";

import { useEffect, useState } from "react";

export default function ClientWidget() {
  const [data, setData] = useState(null);

  useEffect(() => {
    // 여기서는 async/await 를 직접 사용할 수 없음
    fetch("/api/data")
      .then((res) => res.json())
      .then(setData);
  }, []);

  return <div>{data ? JSON.stringify(data) : "Loading..."}</div>;
}
핵심: await 를 쓰고 싶다면 해당 파일에 “use client” 가 없어야 합니다.

2️⃣ 하위 컴포넌트도 확인

Server Component가 await 를 사용하면서 Client Component 를 import 하면 에러가 발생합니다.

// ❌ Bad: Server Component가 Client Component를 직접 import
import ClientWidget from "./ClientWidget";

export default async function Page() {
  const data = await getData();
  return (
    <>
      <ClientWidget />   // ← 여기서 에러
      <pre>{JSON.stringify(data)}</pre>
    </>
  );
}
해결: Client Component는 별도의 파일에서 dynamic 으로 ssr: false 로 로드하거나, Server Component 내부에서 렌더링만 하고 로직을 분리합니다.
// ✅ Good: 동적 import (SSR 비활성화)
import dynamic from "next/dynamic";

const ClientWidget = dynamic(() => import("./ClientWidget"), {
  ssr: false,
});

export default async function Page() {
  const data = await getData();
  return (
    <>
      <ClientWidget />
      <pre>{JSON.stringify(data)}</pre>
    </>
  );
}

3️⃣ 클라이언트 측에서 비동기 로직을 처리하는 패턴

  • useEffect + fetch / axios
  • SWR, React Query 등 데이터 페칭 라이브러리
  • Server Action (Next.js 14에서 제공) 사용 시 use server 를 명시하고, 클라이언트에서는 formAction 으로 호출
"use client";

import { useState } from "react";

export default function SubmitForm() {
  const [msg, setMsg] = useState("");

  async function handleSubmit(e) {
    e.preventDefault();
    const form = e.target;
    const data = new FormData(form);
    const res = await fetch("/api/submit", { method: "POST", body: data });
    const result = await res.json();
    setMsg(result.message);
  }

  return (
    <form onSubmit={handleSubmit}>
      <input name="name" required />
      <button type="submit">전송</button>
      <p>{msg}</p>
    </form>
  );
}

4️⃣ 서버 전용 로직을 별도 파일에 두기

복잡한 데이터 조회·가공 로직은 src/lib/ 같은 디렉터리에서 순수 Node 환경 함수로 구현하고, Server Component에서만 import 합니다.

// src/lib/getPosts.ts
export async function getPosts() {
  const res = await fetch("https://jsonplaceholder.typicode.com/posts");
  return res.json();
}
// src/app/posts/page.tsx  (Server Component)
import { getPosts } from "@/lib/getPosts";

export default async function PostsPage() {
  const posts = await getPosts(); // ✅ Server side
  return (
    <ul>
      {posts.map((p) => (
        <li key={p.id}>{p.title}</li>
      ))}
    </ul>
  );
}

요약 체크리스트

파일 최상단에 “use client” 가 있나요?없애면 Server Component, 필요하면 명시
하위 컴포넌트가 Client Component인가?dynamic(..., { ssr: false }) 로 로드하거나 별도 파일에서 사용
await 를 클라이언트 코드 안에서 직접 사용했나요?useEffect/데이터 페칭 라이브러리로 대체
서버 전용 로직을 src/lib/ 등으로 분리했나요?Server Component에서만 import
위 사항을 점검하고 코드를 정리하면 “async/await is not yet supported in Client Components” 오류가 사라집니다. 추가적인 에러 메시지나 코드가 있으면 공유해 주세요—더 구체적인 도움을 드릴 수 있습니다!
Next.js 14에서 서버 컴포넌트 에러 해결 방법