CSR·SSR·정적 생성과 프레임워크 선택
CSR·SSR·정적 생성에서 수집기가 받는 본문을 비교한다. Next.js 빌드가 만드는 결과물과 갱신 방식을 살펴보고, 검색·AI 답변에 사용할 자료가 실제로 전달되는지 확인한다.
화면에는 같은 글이 보여도 수집기가 받은 자료는 다를 수 있다
일요일 운영 안내가 화면에 보이려면 어딘가에서 데이터를 읽고 HTML 요소를 만들어야 한다. 브라우저가 이 일을 하면 서버는 처음에 로딩 화면만 보낼 수 있다. 서버에서 미리 만들면 운영 시간과 휴관일을 응답 본문에 넣어 보낼 수 있다. SEO·GEO·AEO에서 이 차이가 필요한 이유는 검색·답변 시스템이 사용할 자료를 그 응답과 후속 처리에서 얻기 때문이다.
다음은 같은 안내를 제공하는 두 방식의 본문 부분이다. CSR 예는 브라우저에서 JavaScript로 본문을 채우는 구성이고, 서버 생성 예는 SSR 또는 정적 생성으로 본문을 넣은 구성이다.
<!-- 브라우저에서 본문을 조회하는 구성의 최초 응답 -->
<main id="guide">안내를 불러오는 중입니다.</main>
<script src="/guide.js" defer></script>
<!-- 본문을 서버에서 생성한 구성의 응답 -->
<main><article>
<h1>도서관 일요일 운영 안내</h1>
<p>일요일은 10~17시 운영합니다. 첫째 일요일과 공휴일은 쉽니다.</p>
<p>2026년 10월부터 적용합니다.</p>
<a href="/policies/opening-hours">운영 시간 안내 원문</a>
</article></main>
첫 응답에는 휴관일이 없다. /guide.js를 실행하고 필요한 자료까지 가져와야 알 수 있다. 둘째 응답에는 답과 예외, 적용일, 근거 링크가 이미 있다. HTML을 읽는 도구는 추가 화면 조립 없이 이 자료를 얻는다. 먼저 이 차이를 확인한 뒤, 본문을 언제 만들 것인지 선택한다.
본문을 받는 단계가 검색 결과와 AI 답변으로 이어진다
검색 시스템은 가져온 문서에서 내용을 처리해 색인에 넣고, 질문에 맞는 자료를 선택한다. 페이지가 “첫째 일요일 휴관”을 전달하지 못하면 그 페이지에서 해당 조건을 얻을 수 없다. 본문을 응답 HTML에 넣으면 이 정보가 JavaScript 실행과 추가 API 요청의 성공에만 달려 있는 상태를 줄인다.
Google은 JavaScript를 실행해 CSR 본문도 처리한다. 이때 수집 후 렌더링을 거치며, 차단된 자원이나 실패한 요청 때문에 내용이 빠질 수 있다. SSR·사전 렌더링은 핵심 본문을 응답에 제공하는 방법이다. Google은 모든 봇이 JavaScript를 실행할 수 있는 것은 아니라는 점도 설명한다. Google의 JavaScript 처리 과정
웹 자료를 쓰는 생성형 답변에도 읽을 문서가 필요하다. Google 생성형 검색에서는 색인과 스니펫 표시 자격이 참여 조건에 포함된다. 따라서 본문 전달 문제를 고치는 일은 답변의 근거 후보가 될 문서를 검색이 처리할 수 있게 하는 과정과 연결된다. 그다음에는 질문과의 관련성, 사실과 조건의 충분성, 실제 출처 선택을 확인한다. Google 생성형 검색 요건
예를 들어 “2026년 11월 1일 방문할 수 있는가”에 답하려면 일요일 운영 시간과 첫째 일요일 휴관 조건을 함께 읽어야 한다. 서버 본문에 시간만 넣으면 전달 방식은 바뀌어도 답의 재료가 부족하다. 렌더링은 자료를 전달하는 부분을 해결하고, 원고는 판단에 필요한 사실을 제공한다. 외부 AI 서비스별 수집·조회 방식은 각 서비스의 문서와 실제 인용 결과로 확인한다.
CSR과 SSR은 데이터를 읽고 본문을 만드는 위치가 다르다
CSR(Client-Side Rendering)은 브라우저에서 화면을 만드는 방식이다. 본문을 브라우저에서 조회하는 구성은 HTML 수신 → JavaScript 다운로드·실행 → API 요청 → 단락 생성 순서로 진행된다. 어느 단계에서 실패했는지에 따라 로딩 화면이 남거나 일부 정보만 표시될 수 있다.
SSR(Server-Side Rendering)은 요청을 받은 서버가 데이터를 읽고 HTML을 만드는 방식이다. 공개 안내를 서버에서 조회해 h1·p·a 요소를 만들면 그 응답에 제목·조건·근거가 들어간다. 브라우저는 받은 글을 표시하고, 필요한 버튼 동작을 이후에 연결한다.
SSR에서는 데이터 조회 지연이나 서버 오류가 응답에 영향을 준다. 변경이 드문 같은 안내를 요청마다 새로 만들 필요가 없다면 정적 생성이나 캐시를 선택할 수 있다. 생성 방식은 자료를 읽을 수 있는지와 얼마나 빨리 갱신해야 하는지를 함께 보고 정한다.
정적 생성은 요청 전에 HTML을 만들어 두는 방식이다
정적 생성(SSG, Static Site Generation)은 방문 요청이 들어오기 전에 경로별 HTML을 만드는 방식이다. 예를 들어 빌드할 때 소개 글과 이용 안내를 읽어 각 URL의 HTML을 생성하고 CDN에서 제공한다. 사용자가 접속할 때마다 DB를 조회해 같은 페이지를 다시 만들지 않아도 된다. 제목·본문·링크가 HTML에 있으므로 검색 수집 관점의 핵심 이점은 SSR과 공유한다.
정적으로 생성한 페이지에도 버튼과 검색창을 넣을 수 있다. React는 미리 만든 HTML에 이벤트 처리 등 상호작용을 연결하는데, 이를 하이드레이션(hydration)이라고 한다. 정적 호스팅에 올린 파일이 경로별 본문을 포함하는지는 별도로 확인한다. 모든 URL이 같은 빈 index.html을 받고 브라우저에서 본문을 채운다면 그 본문은 여전히 CSR로 제공된다.
SSG의 운영 과제는 갱신이다. 빌드 뒤 CMS에서 글을 고쳐도 이미 만든 HTML은 자동으로 바뀌지 않는다. 재빌드·재배포를 하거나, 지원되는 런타임에서 해당 경로를 재생성하도록 연결해야 한다. ISR(Incremental Static Regeneration)은 미리 만든 페이지를 일정 조건이나 갱신 요청에 따라 다시 생성하는 방식이다. 사용 중인 Next.js 버전과 캐시 설정에 맞춰 재검증 API와 게시 이벤트를 연결한다.
일정 시간 뒤 갱신하는 방식은 그동안 이전 글이 남을 수 있다. 글 철회나 접근 권한 변경을 즉시 반영해야 한다면 시간 만료만 기다리지 않도록 캐시 무효화와 요청 시 공개 판정을 설계한다. 배경 재생성을 사용하는 설정은 갱신 중 이전 응답을 줄 수 있으므로 게시·철회 직후 첫 요청도 확인한다.
Next.js 빌드는 경로별 HTML과 서버 실행 코드를 준비한다
빌드는 소스 코드를 배포할 결과물로 바꾸는 작업이다. 일반적인 React SPA 빌드는 JavaScript와 HTML 진입점을 만들고, 본문은 브라우저가 채우게 할 수 있다. Next.js에서는 경로의 데이터 조회와 설정에 따라 미리 생성할 HTML과 요청 때 실행할 서버 코드를 준비한다. 두 경우 모두 빌드 명령은 성공할 수 있으므로, 결과에 페이지의 본문이 언제 들어오는지를 읽어야 한다.
뒤의 Next.js 구현 실습에서 /archive/opening-2025는 고정된 과거 안내를 빌드 때 만들고, /guides/[slug]는 요청마다 현재 게시본을 읽는다. 운영 서버는 첫 경로에 이미 생성한 HTML을 제공하고, 둘째 경로에는 서버 코드를 실행해 만든 응답을 제공한다. 두 경로 모두 수집기에 본문을 보낼 수 있지만 수정 반영 시점은 다르다.
정적 경로는 빌드 때 사용한 원고를 계속 제공하므로 원고 수정 후 재생성해야 한다. 요청 시 생성 경로는 새 요청에서 새 자료를 읽을 수 있지만, 조회 캐시가 있다면 그 캐시도 갱신해야 한다. 빌드 완료 뒤 확인할 대상은 생성된 경로, 실제 HTML, 그리고 수정 후 첫 응답의 내용이다.
output: export를 사용하면 Next.js는 out 디렉터리에 배포할 HTML·CSS·JavaScript를 만든다. 이 파일들은 정적 서버에서 제공할 수 있다. 요청마다 서버 코드를 실행하는 기능과 ISR은 서버 런타임을 사용하는 배포에서 구성한다. Next.js 정적 내보내기
예제 파일에서 데이터 조회와 HTML 출력을 찾는다
React는 화면을 컴포넌트(component)로 나누어 구성하는 라이브러리다. 컴포넌트는 제목이나 글 목록처럼 재사용할 화면 단위다. JSX는 JavaScript 안에서 HTML과 비슷한 표기로 화면 구조를 쓰는 문법이다. TypeScript는 데이터 형태를 검사할 수 있도록 JavaScript에 타입을 더한 언어다. tsx 파일은 TypeScript와 JSX를 함께 쓴다.
빌드(build)는 작성한 코드를 실행 환경에 맞게 변환하고 묶는 작업이다. 번들(bundle)은 그렇게 묶은 코드 파일이다. 개발 서버는 수정 결과를 빠르게 보여주고, 운영 빌드는 실제 배포할 결과물을 만든다. 런타임(runtime)은 그 결과물을 실행하는 환경이며 브라우저와 서버가 각각의 코드를 실행한다.
Next.js의 App Router는 app 디렉터리 구조로 URL과 페이지를 연결한다. page.tsx는 해당 주소의 페이지, layout.tsx는 여러 페이지가 공유하는 구조, route.ts는 HTTP 요청을 받아 응답하는 처리기를 정의한다. [slug]는 주소의 가변 부분이다. /guides/opening-hours에서는 opening-hours가 slug 값이 된다. src/app을 사용하는 저장소도 있다.
generateMetadata는 페이지 데이터에서 제목·설명·대표 주소를 만드는 함수다. API(Application Programming Interface)는 프로그램이 정해진 형식으로 자료나 동작을 요청하는 접점이다. 공개 페이지의 서버 함수가 DB를 직접 읽거나 내부 API를 호출할 수 있다. 브라우저에 DB 접속 정보를 보내지 않고 서버에서 공개 조건을 적용한다.
import는 다른 파일의 코드를 가져오고 await는 비동기 조회 결과를 기다린다. useEffect는 컴포넌트가 브라우저에 반영된 뒤 추가 작업을 실행한다. 공개 본문을 useEffect에서만 조회하면 앞의 로딩 화면과 같은 응답이 나올 수 있다. 서버 page에서 자료를 읽어 JSX의 p 요소로 출력하면 서버가 만드는 본문에 그 자료를 포함할 수 있다.
Next.js를 써도 본문이 어디서 생성되는지 추적한다
App Router의 page와 layout은 기본적으로 Server Component다. 서버 쪽에서 데이터를 읽을 수 있고, 정적 생성과 캐시 설정에 따라 실행 시점이 달라진다. Server Component는 컴포넌트의 실행 경계이고 SSR·SSG는 HTML 생성 시점에 관한 구분이다.
use client가 붙은 컴포넌트도 첫 페이지 로드에서는 서버에서 HTML을 미리 만들 수 있다. 핵심 본문이 useEffect 이후에 생기는지, 브라우저 전용 조건에 가려지는지, 해당 영역의 서버 렌더링이 꺼져 있는지를 확인한다. Server·Client Component 설명을 바탕으로 데이터가 들어오는 시점을 확인한다.
공개 글이 effect에서만 조회된다면 조회를 서버 page로 옮기고, 현재 공개 원고의 제목·본문·출처를 렌더링한다. 좋아요·공유·필터처럼 상호작용이 필요한 부분만 작은 Client Component로 나눈다. 서버에서 받은 본문을 브라우저 초기 상태가 빈 값으로 덮지 않는지 확인한다. 서버에 한 번 나타난 문장이 hydration 뒤 사라지는 경우도 검사한다.
CMS 편집기의 작업본과 게시본을 구분하고 본문과 메타데이터가 같은 공개 버전을 읽게 한다. 렌더링 방식만 옮기면서 임시 저장본을 조회하면 검색 문제를 고치려다 비공개 원고를 노출할 수 있다. 공개 조회 함수에서 현재 게시된 버전을 선택한 뒤 본문과 메타데이터에 전달한다.
Vite와 Next.js의 서버 렌더링 구성을 비교한다
Vite는 개발 서버와 빌드 도구다. SPA(Single-Page Application)는 하나의 문서에서 JavaScript로 화면을 전환하는 애플리케이션이다. 일반적인 Vite 기반 React SPA 구성에서는 애플리케이션 JavaScript와 HTML 진입점을 빌드한다. 이 구성에서 글을 useEffect로 조회하면 페이지별 본문 생성은 브라우저가 맡는다. 페이지별 HTML·대표 주소·사이트맵이 필요하면 서버 렌더링이나 사전 생성 및 메타데이터 생성 기능을 구성한다.
Vite에도 SSR 기능이 있다. 서버 진입점에서 컴포넌트를 렌더링하고 결과를 HTML에 넣도록 구성하거나, Vite 기반 SSR·정적 생성 프레임워크를 사용할 수 있다. 이때도 요청 처리, 데이터 조회, 라우트별 head, 404·리다이렉트, 캐시와 갱신 방식을 선택해야 한다. Vite SSR 안내는 이 기능을 제공하는 저수준 API와 서버·클라이언트 진입점을 설명한다.
Next.js는 이보다 넓은 애플리케이션 구조를 제공한다. App Router의 page·layout, 서버 데이터 조회, 정적·동적 렌더링, Metadata API, robots·sitemap 파일 규약, 리다이렉트와 배포 런타임을 한 구조에서 다룰 수 있다. 예를 들어 CMS 게시본을 조회한 뒤 본문, generateMetadata, JSON-LD를 같은 자료에서 만들고 게시 변경에 맞춰 관련 캐시를 갱신할 수 있다.
공개 소개와 보존 자료는 미리 만들고, 새로 게시되는 글은 현재 게시본을 읽으며, 상세마다 제목·대표 주소·출처를 제공해야 하는 사이트라면 이 통합 구조가 선택 근거가 된다. 페이지 개편 뒤에도 라우트·메타데이터·사이트맵·서버 응답을 같은 애플리케이션 안에서 추적하기 쉽다. 공개 조건을 여러 곳에 따로 구현하면서 생기는 누락을 줄일 수 있다. 검색 시스템이 수집하는 결과는 이 구조에서 출력한 HTML·링크·메타데이터다.
Vite 기반 구성에서도 같은 공개 HTML·메타데이터·상태 코드·갱신 기능을 제공할 수 있다. 두 구성을 비교할 때는 직접 구현할 라우팅·서버 조회·캐시 코드의 양, 배포 환경의 지원 기능, 팀의 유지보수 경험을 함께 본다. 이미 안정적으로 동작하는 구성은 이 요구를 충족하는지부터 확인한다.
CMS 안내 수백 편의 제목·본문·canonical을 각각 다른 코드에서 만들면 새 콘텐츠 유형을 추가할 때 한 경로를 빠뜨리기 쉽다. Next.js를 선택할 실무적 이유는 라우트별 조회와 Metadata API, 사이트맵 생성을 같은 자료와 파일 구조로 관리할 수 있다는 점이다. 이 구성으로 실제 출력의 누락과 불일치를 줄일 수 있는지 평가한다. 이미 같은 응답과 갱신 동작을 제공하는 Vite SSR이나 다른 서버 구성도 이 요구를 충족한다.
페이지별로 생성 시점과 갱신 방법을 결정한다
소개나 보존 안내처럼 배포 사이에 내용이 바뀌지 않는 페이지는 정적 생성으로 제공할 수 있다. CMS에서 수시로 게시하고 철회하는 상세 글은 요청 때 현재 게시본을 읽거나 게시 이벤트로 캐시를 갱신해야 한다. 개인화된 관리자 화면은 인증과 사용자별 데이터를 먼저 처리한다.
한 사이트 안에서 이 방식을 함께 사용할 수 있다. URL 종류별로 생성 시점, 이전 내용을 제공해도 되는 시간, 장애 시 응답을 정한다. SSR 페이지 안에서도 먼저 보낼 공통 구조와 나중에 보낼 자료를 스트리밍으로 나눌 수 있다.
서버 조회를 기다린 뒤 응답을 시작하면 그 대기 시간이 첫 바이트 도착 시간에 포함된다. 먼저 화면 틀을 스트리밍하는 경우에는 본문 조회가 첫 바이트 뒤에 끝날 수 있다. 첫 바이트 시간과 실제 본문 표시 시간을 함께 측정한다.
수정 전후 HTML과 실제 검색 처리를 순서대로 비교한다
실습의 설치·실행 절차를 마친 뒤 아래 명령을 실행한다. 두 URL의 완성된 응답을 각각 저장한다. curl은 JavaScript를 실행하지 않으므로 브라우저가 나중에 요청해서 채운 글은 가져오지 않는다.
curl -sS -D current.headers -o current.html http://localhost:3027/guides/opening-hours
curl -sS -D archive.headers -o archive.html http://localhost:3027/archive/opening-2025
current.html에서는 운영 시간·첫째 일요일 휴관·적용 시작일을, archive.html에서는 2025년 적용 기간과 현재 안내 링크를 찾는다. HTML 파서 검사는 문자열이 script 데이터에만 있는 경우를 구분하고 article의 본문·링크·날짜를 비교한다. 스트리밍 구성에서는 응답 전체와 브라우저의 완성 DOM을 함께 읽는다.
다음으로 CMS 자료나 실습의 고정 원고를 수정하고 같은 주소를 다시 요청한다. 정적 페이지는 재빌드 뒤, 요청 시 생성 페이지는 새 요청과 필요한 캐시 갱신 뒤에 새 문장이 나와야 한다. 이를 통해 선택한 방식이 실제 갱신 요구를 충족하는지 확인한다.
운영에 적용한 뒤에는 Search Console의 수집·렌더링 결과와 최근 수집일을 본다. 웹 검색을 사용하는 AI에는 같은 기준일의 질문을 실행해 인용 URL과 휴관 조건을 읽는다. 서버 응답에 새 문장이 있는지, 검색이 새 문서를 처리했는지, 답변이 그 조건을 사용했는지 순서대로 비교하면 다음에 고칠 위치를 좁힐 수 있다.
SSR이 만든 HTML에 img가 들어 있으면 브라우저는 그 주소를 발견해 별도의 이미지 요청을 보낸다. HTML에 운영 시간은 즉시 있어도 사진 주소가 5MB 원본이면 사진의 전송과 디코딩은 이어서 발생한다. Next.js 빌드 성공 후에도 CMS 사진의 currentSrc와 응답 바이트를 읽어야 하는 이유다. CMS 이미지 전달 실습은 HTML 생성 방식을 고정한 채 원본 요청과 파생본 요청만 바꿔 비교한다.