Next.js 13+ 로딩 마스터: loading.js와 Suspense의 관계 완벽 정리
Server Components(RSC) 시대로의 전환, 'Instant Loading'을 이해하는 법
Next.js Pages Router에서 App Router로 넘어오면서 가장 체감되는 변화 중 하나는 바로 데이터 페칭과 로딩 처리 방식입니다.
과거에는 `useEffect` 안에서 데이터를 가져오고 `isLoading` 상태를 직접 관리했다면, 이제는 파일 시스템 하나로 우아한 처리가 가능해졌습니다.
❓ 의문점
"그냥 `loading.js` 파일을 만들면 로딩 화면이 뜬다던데, 도대체 무슨 원리일까?"
"내가 직접 쓰는 `
이 글에서는 Next.js가 loading.js를 어떻게 처리하는지, 그리고 이것이 React Suspense와 어떤 관계인지 명확히 짚어드리겠습니다.
서버 사이드 렌더링의 핵심인 스트리밍(Streaming) 기술을 이해하면, 여러분의 웹사이트 속도는 체감상 2배 더 빨라질 것입니다.
📂 1. loading.js는 사실 '자동화된 Suspense'다
결론부터 말씀드리면, Next.js의 loading.js는 마법이 아닙니다.
빌드 타임에 Next.js는 `loading.js` 파일이 존재하면, 해당 경로의 `page.js`를 자동으로 React Suspense 컴포넌트로 감싸버립니다.
🖥️ 우리가 작성한 파일 구조
- app/
- ├── dashboard/
- │ ├── loading.js
- │ └── page.js
⚙️ Next.js가 변환한 실제 코드 형태
<Header />
<SideNav />
<Suspense fallback={<Loading />}>
<Page />
</Suspense>
</Layout>
즉, `loading.js`는 페이지 전체(혹은 해당 레이아웃 하위 세그먼트)에 대한 "즉시 로딩 상태(Instant Loading State)"를 정의하는 파일 시스템 규칙일 뿐입니다.
이 덕분에 서버 컴포넌트가 데이터를 다 가져올 때까지 브라우저가 하얀 화면으로 멈춰있는 것을 방지할 수 있습니다.
🌊 2. 서버 사이드 스트리밍(Streaming)의 마법
기존의 SSR(Server-Side Rendering)은 데이터가 준비될 때까지 HTML을 전혀 보내지 못하는 'Waterfalls' 문제가 있었습니다.
하지만 `loading.js`와 `Suspense`를 활용한 RSC 아키텍처는 HTML을 조각조각 나누어 스트리밍합니다.
🚀 스트리밍 처리 순서
-
1단계 (즉시 전송): 서버는 요청 즉시, 레이아웃(`layout.js`)과 로딩 UI(`loading.js`)가 포함된 HTML 껍데기를 먼저 브라우저로 보냅니다.
-
2단계 (데이터 대기): 서버에서 `page.js` 내부의 비동기 함수(`await fetchData()`)가 실행되는 동안, 사용자는 스켈레톤 UI를 보고 있습니다.
-
3단계 (치환): 데이터 로딩이 완료되면, 서버는 나머지 HTML 조각과 데이터를 전송하고, React는 스켈레톤을 실제 콘텐츠로 Swap합니다.
이 과정은 브라우저가 페이지를 새로고침 하지 않아도 자연스럽게 일어납니다.
이것이 바로 Next.js 13+가 제공하는 TTFB(Time To First Byte)와 FCP(First Contentful Paint) 최적화의 핵심입니다.
⚖️ 3. 언제 loading.js를 쓰고, 언제 Suspense를 쓸까?
`loading.js`는 페이지 단위의 큰 로딩을 처리하기엔 좋지만, 페이지 내부의 일부분만 로딩하고 싶을 때는 적합하지 않을 수 있습니다.
이때는 우리가 직접 `
| 구분 | loading.js (파일 기반) | <Suspense> (직접 사용) |
|---|---|---|
| 적용 범위 | 페이지 전체 (Page Segment) | 컴포넌트 단위 (Component Level) |
| 장점 | 구현이 매우 쉽고 자동화됨 | 필요한 부분만 로딩시켜 UX 최적화 |
| 추천 상황 | 초기 진입 시 전체 레이아웃 로딩 | 무거운 차트, 댓글 목록 등 일부 섹션 |
export default function Dashboard() {
return (
<>
<h1>대시보드</h1>
{/* 느린 컴포넌트만 별도로 로딩 처리 */}
<Suspense fallback={<SkeletonChart />}>
<RevenueChart />
</Suspense>
<RecentActivity />
</>
);
}
위 코드처럼 작성하면, `RevenueChart`가 데이터를 불러오는 동안에도 사용자는 `RecentActivity` 같은 다른 컴포넌트를 즉시 볼 수 있습니다. 이것이 병렬 데이터 페칭(Parallel Data Fetching)의 이점입니다.
✨ 요약 및 마무리
Next.js 13+의 로딩 시스템은 개발자에게는 편리함(loading.js)을, 사용자에게는 속도(Streaming)를 제공하는 강력한 도구입니다.
이제 더 이상 데이터를 기다리며 빈 화면을 보여주지 마세요.
📝 핵심 포인트 3줄 요약
- loading.js는 `page.js`를 감싸는 자동화된 Suspense Boundary다.
- 서버는 HTML 스트리밍을 통해 껍데기(UI)를 먼저 보내고, 알맹이(Data)를 나중에 채워 넣는다.
- 페이지 전체 로딩은 loading.js, 부분 로딩 최적화는 Manual Suspense를 사용해라.

댓글 쓰기