유리의 개발새발
[Next] 08. SSG 본문
Next.js에서 SSR(Server Side Rendering)은 가장 기본적인 렌더링 방식입니다.
사용자가 페이지에 접속하면, 서버는 실시간으로 데이터를 불러오고, 그 데이터를 기반으로 HTML을 생성한 뒤 사용자에게 전달합니다.
하지만 만약 데이터를 가져오는 API 서버가 물리적으로 멀리 떨어져 있거나(예: 아프리카에 위치한 서버), 혹은 가져와야 할 데이터 양이 많아 시간이 오래 걸린다면, 사용자는 페이지가 로딩될 때까지 그만큼 기다려야 합니다.
즉, 서버 응답이 느려지면 사용자 경험도 함께 저하되는 것이죠.
그렇다면 어떻게 해야 할까요?
이럴 땐 SSR 대신 SSG(Static Site Generation) 방식을 사용하는 것이 좋습니다.
SSG는 페이지를 빌드 시점에 미리 정적으로 생성해두는 방식으로, 사용자의 요청 시 서버가 실시간으로 처리할 필요 없이 빠르게 응답할 수 있다는 장점이 있습니다.
SSG의 핵심은 '빌드 타임 사전 렌더링'
SSG의 가장 큰 특징은, 빌드 타임(npm run build)에 페이지를 미리 사전 렌더링해둔다는 점입니다.
즉, 사용자가 요청하기 전에 이미 정적인 HTML 파일이 생성되어 있으며, 그 이후에는 별도로 페이지를 다시 생성하지 않습니다.
“약간 Static 같은 개념인가요?” → 이 부분은 나중에 따로 정리해보겠습니다.
그런데, 장점만 있을까요?
그럴 리는 없겠죠.
SSG는 빌드 타임 이후에는 페이지를 다시 생성하지 않기 때문에, 사용자가 언제 접속하더라도 항상 동일한 페이지를 응답하게 됩니다.
이러한 특성 때문에, 변경이 자주 일어나지 않는 정적인 콘텐츠에 특히 적합한 렌더링 방식입니다.
예를 들어, 회사 소개 페이지, 블로그 글, 공지사항 페이지처럼 한 번 만들어두면 내용이 자주 바뀌지 않는 페이지들이 SSG에 잘 어울립니다.
어떻게 적용하나요?
아래는 기존에 SSR로 되어있는 코드입니다.
getServerSideProps를 호출하고 있죠?
이걸 getStaticProps로 바꿉니다. 이러면 더이상 SSR이 아니고 SSG 방식으로 동작하게 됩니다.


이렇게 하면 된다고는 하는데... 페이지를 새로고침할 때마다 render check 같은 로그가 계속 찍히는 걸 보셨을 수도 있습니다.
"아니, 분명 SSG는 빌드 타임 이후에는 페이지를 다시 생성하지 않기 때문에,
사용자가 언제 접속하더라도 항상 동일한 페이지를 응답한다면서요?
그런데 왜 자꾸 다시 렌더링되는 것처럼 보일까요?"
그.것.은..........................
👉 개발 모드(dev 모드)라서 그렇습니다.
Next.js에서는 next dev로 개발 서버를 실행할 경우,
매 요청마다 페이지를 새로 생성합니다. 즉, 실제 SSG 방식으로 동작하지 않고, SSR처럼 작동합니다.
이는 개발 중에 코드를 바꿨을 때 바로바로 반영되도록 하기 위한 동작입니다.
실제로 npm run build → npm start 로 프로덕션 모드에서 실행해보면,
해당 로그는 딱 한 번만 찍히고 이후로는 재렌더링되지 않습니다.
🤔 그런데 궁금증이 하나 생깁니다.
API로 받아오는 데이터는요?
처음에 한 번 받고, 그 이후로는 아무 일도 일어나지 않는 건가요?
맞대요.
npm run build 할 때만 실행되고,
사용자가 접속할 때는 이미 만들어져 있는 정적 HTML만 전달됩니다.
즉, 그 이후로는 fetch()도 호출되지 않고, API도 다시 호출되지 않습니다.
SSG는 데이터도 정적입니다.
빌드 시점의 데이터만 반영되고, 이후 변경 사항은 사용자가 절대 알 수 없습니다.
그럼 뭐 어쩌자는건데요...? 생각해보면, 쿼리 스트링 값도 모르겠네요...?
그럼 뭐... 클라이언트에서 하면 되려나? useEffect 내부에서 치면 될지도...?

동작은 하겠져. 근데 그런 방식이 싫어서 Next.js를 쓰는 거잖아요.
SSR이니 SSG니 하는 것도 결국, 데이터를 클라이언트가 아니라 서버에서 먼저 불러오고 싶어서 쓰는 거니까요.
이 부분은 다음 글에서 해결됩니다! 일단 넘어가죠.
또 기존의 리액트처럼 완전히 동일하게 동작하는 건 아닙니다.
넥스트에서 기본적으로 SSG 방식으로 렌더링 한다잖아요? 근데 쿼리스트링 같은건 최초에는 모르잖아요.
그럼 넥스트는 지가 할 수 있는 부분까지만 미리 렌더링 한답니다. 예를 들어 div 태그 같은것들을 먼저 렌더링하고 후에 저 페이지에 접근하면 그 때 추가로 렌더링하는 방식이래요.
++
넥스트에서는 어떤 페이지에 아무 렌더링 설정도 안해두면, SSG 방식으로 동작합니다.
동적 경로에서는 어쩌죠? .../[id] 디렉토리에서는 못쓰나요?

이러면 에러가 터집니다.
에러 로그를 볼까요?

🧭 동적 경로에서는 어떻게 해야 할까요?
Next.js에서 SSG를 적용할 때,
/about, /contact처럼 고정된 경로는 아무 문제 없이 정적 생성이 가능합니다.
하지만 /posts/[id]처럼 동적 라우팅(Dynamic Routing)이 들어간 경우에는 이야기가 달라집니다.
"빌드 타임에는 [id]에 어떤 값이 들어올지 알 수 없잖아요?"
→ 맞습니다. 그래서 Next.js에 "어떤 경로들이 존재할 수 있는지"를 알려주는 작업이 필요합니다.
이 역할을 해주는 함수가 바로 에러 로그에서 종종 보이는 getStaticPaths입니다.
간단히 말해, getStaticPaths는 빌드 시점에 미리 생성해야 할 동적 경로들을 정의하는 함수입니다.

여기서 params 안의 값들은 문자열이어야 합니다.
예: 숫자 ID라도 '1', '2'처럼 문자열로 작성해야 합니다.
🤔 그럼 fallback은 뭔가요?
fallback은 간단히 말해, paths에 없는 값으로 접속하면 어떻게 처리할지를 설정하는 옵션입니다.
- fallback: false
- paths에 없는 경로로 접속하면 → 404 (Not Found) 페이지로 이동
- 즉, 지정된 경로만 사전 생성, 그 외는 차단
- 그닥 안쓰일 것 같은데요.
- fallback: true
- paths에 없는 경로로 접속해도 일단 페이지 진입
- 백그라운드에서 새로 HTML을 생성한 뒤, 다음 요청부터는 캐싱된 HTML 사용
- 초기 로딩 중엔 로딩 스피너 처리 필요
- fallback: 'blocking'
- paths에 없는 경로로 접속하면 → 서버가 HTML을 다 만들 때까지 기다림
- 클라이언트는 로딩 상태 없이 바로 완성된 페이지를 받음
- 첫 요청만 느릴 뿐, 이후엔 캐시된 HTML 제공
blocking과 true가 좀 헷갈리네요
true / 'blocking'
| 경로 처리 방식 | 일단 페이지부터 보여줌 | HTML 생성 끝날 때까지 기다림 |
| HTML 생성 시점 | 백그라운드에서 생성 | 요청과 동시에 생성 |
| 사용자 입장 | 로딩 중 먼저 보임 → 이후 데이터 표시 | 완성된 페이지가 바로 뜸 (로딩 없음) |
| 페이지 첫 진입 시 | 데이터 없음 → isFallback으로 분기 필요 | 데이터 포함된 상태로 바로 표시됨 |
| 페이지 UX | 로딩 스피너 등 별도 처리 필요 | 부드러운 전환 (SSR 느낌) |
| 재접속 시 | 캐시된 정적 HTML 사용 | 동일하게 캐시 사용 |
🧪 동작 흐름 예시
① fallback: true
- 사용자가 /posts/123에 접속
- paths에 '123'이 없으면:
- 일단 비어 있는 페이지부터 뜸 (getStaticProps는 아직 실행되지 않음)
- 이때 <h1>로딩 중입니다...</h1> 같은 걸 먼저 보여줘야 함
- 백그라운드에서 getStaticProps 실행 → HTML 생성
- 생성 완료 후 자동 교체 or 리렌더링
- 다음 사용자는 정적 HTML을 받음
개발자는 router.isFallback을 활용해 "로딩 중인지" 판단해서 처리해야 함
if (router.isFallback) {
return <LoadingSpinner />;
}
② fallback: 'blocking'
- 사용자가 /posts/123에 접속
- paths에 '123'이 없으면:
- 서버가 즉시 getStaticProps 실행 → HTML 생성
- 그게 끝날 때까지 사용자한테 아무것도 안 보임
- 생성 완료 후, 완성된 HTML 통째로 클라이언트에 전송
- 이후 요청부터는 정적 HTML 사용
개발자가 별도로 isFallback 처리를 할 필요가 없음

'Next' 카테고리의 다른 글
| [Next] 10. SEO (3) | 2025.07.31 |
|---|---|
| [Next] 09. ISR (4) | 2025.07.31 |
| [Next] 07. 사전 렌더링과 데이터 페칭 (SSR방식으로 조금) (3) | 2025.07.30 |
| [Next] 06. Pre-fetching (0) | 2025.07.29 |
| [Next] 05. Next Navigation (0) | 2025.07.29 |