웹 개발에서 SSR과 CSR은 렌더링 방식을 나타내는 핵심 아키텍처 개념입니다. 렌더링은 결국 HTML을 언제 어디서 완성해서 사용자에게 보여줄지를 결정하는 과정이에요.
서버사이드 렌더링은 서버에서 HTML을 미리 생성해서 클라이언트(브라우저)에 전달하는 방식입니다. 사용자가 페이지를 요청하면, 서버에서 HTML을 동적으로 생성하고 완성된 HTML 파일을 클라이언트에 전송하여 바로 페이지를 표시합니다.
SSR은 서버에서 HTML을 생성해서 클라이언트에게 보내는 아키텍처이기 때문에 서버가 꼭 JS일 필요가 없어요. 서버가 하는 건 “HTML 문자열을 생성해서 클라이언트에게 보내기”이니까, PHP, Python, Java, Ruby, C#, Node.js 등 서버에서 실행 가능한 언어라면 전부 가능합니다.
블로그 사이트에서 "최근 포스트" 목록을 보여주는 경우를 살펴보겠습니다.
<!-- 서버가 클라이언트에게 전송한 HTML -->
<html>
<head>
<title>최근 포스트</title>
</head>
<body>
<h1>최근 포스트</h1>
<ul>
<li>포스트 1</li>
<li>포스트 2</li>
<li>포스트 3</li>
</ul>
</body>
</html>
서버사이드 렌더링에서는 사용자가 페이지를 요청하면, 서버에서 "최근 포스트" 데이터를 가져와서 HTML로 변환한 후, 완성된 HTML 페이지를 클라이언트(사용자의 브라우저)에게 보냅니다. 그러면 브라우저는 이 HTML을 바로 렌더링하여 사용자에게 페이지를 표시합니다.
[SSR HTML] → 브라우저에 바로 보여짐 (빠른 화면)
↘
[React hydrate 진행] → 이벤트/상태 바인딩
↘
[인터랙티브 SPA] → 클릭, 입력 등 동작 가능
클라이언트 사이드 렌더링은 서버가 빈 HTML 파일만 보내고, 브라우저에서 JavaScript를 실행해서 DOM을 구성하고 화면을 그리고 방식입니다. 서버는 기본 HTML 구조만 전송하고, 클라이언트(브라우저)에서 JavaScript를 통해 페이지의 내용이 동적으로 로드되고 렌더링됩니다.
CSR은 본질적으로 브라우저 안에서 동작하는 방식이기 때문에 HTML 문서 안에 <script>
로 JS를 불러와서 실행해야 하니까, 언어는 무조건 JavaScript일 수밖에 없어요. 그래서 CSR 얘기할 때는 React, Vue, Angular 같은 JavaScript 기반 프레임워크들이 항상 언급됩니다.
같은 "최근 포스트" 목록을 보여주는 페이지를 예시로 보겠습니다.
<!-- 서버가 클라이언트에 전송한 빈 HTML -->
<html>
<head>
<title>최근 포스트</title>
</head>
<body>
<div id="posts"></div> <!-- JavaScript로 동적으로 채워질 곳 -->
<script src="app.js"></script>
</body>
</html>
// app.js에서 데이터를 받아서 페이지에 동적으로 렌더링
fetch('/api/posts') // 서버에서 포스트 목록을 받아옴
.then(response => response.json())
.then(posts => {
const postsContainer = document.getElementById('posts');
posts.forEach(post => {
const postElement = document.createElement('li');
postElement.textContent = post.title;
postsContainer.appendChild(postElement);
});
});
클라이언트 사이드 렌더링에서는 사용자가 페이지를 요청하면, 서버는 빈 HTML 파일을 전송합니다. 그리고 클라이언트에서는 JavaScript가 실행되면서 API를 호출하여 "최근 포스트" 목록을 서버에서 받아옵니다. 받은 데이터를 이용해 페이지를 동적으로 렌더링합니다.
React는 CSR 중심 라이브러리이고, Next.js는 React를 기반으로 한 풀스택 프레임워크에요.
그래서 CSR도 가능하고, SSR도 가능합니다. 심지어 SSG, ISR(Incremental Static Regeneration)도 지원해요.
즉, React 기반이지만 모든 렌더링 방식을 지원하는 하이브리드 프레임워크입니다.
개발팀에서 CSR에서 SSR로 전환을 검토할 때 마주치는 현실적인 상황을 살펴보겠습니다.
React 기반 CSR 환경에서 직면하는 문제들
Next.js 도입을 통해 기대하는 개선점
하지만 백엔드 관점에서는 여러 현실적인 문제들이 있습니다.
Next.js를 도입하면 서버 구조에도 변화가 필요합니다.
Client ← Nginx (정적 파일) ← CDN
↓
Client ← Spring Boot API ← Database
SSR 도입 후 필요한 구조
Client ← Nginx ← Next.js Server (Node.js) ← Spring Boot API ← Database
CSR은 정적 파일을 웹서버에서 서빙하면 끝이지만, SSR은 요청마다 HTML을 생성해야 하므로 Node.js 서버가 필요합니다. 예를 들어, 기존이 Nginx + Spring
구조라면, SSR을 적용하기 위해서는 Node 서버를 추가해야 합니다. 이로 인한 장애 지점 증가할 수 있습니다. Node.js 서버 다운 시 전체 서비스 영향을 미칩니다.
B2B 서비스의 특징
이런 경우 SSR의 주요 장점인 SEO 개선 효과가 미미합니다. 오히려 서버 비용 증가와 운영 복잡성만 커질 수 있습니다. 이 경우 CSR 방식이 더 단순하고 안정적입니다.
기존 CSR 구조
SSR 도입 후
백엔드 (API 서버)
프론트엔드 (SSR 서버 : Next.js)
클라이언트(브라우저)
<button>좋아요 👍</button>
*<!-- 버튼이 보이지만 onClick 이벤트는 작동하지 않음 -->*
Hydration 이후React가 클라이언트에서 실행되면서 가상 DOM 생성
서버에서 받은 HTML과 비교하여 일치성 확인
이벤트 핸들러 연결 → 완전한 SPA처럼 동작 시작
특징
빠른 첫 화면: HTML을 먼저 보여주므로 초기 로딩 속도 향상
CSR 전환: Hydration 완료 후에는 CSR처럼 동작
성능 고려사항: 페이지가 클수록 Hydration 과정이 무거워질 수 있음
즉, SSR에서도 프론트엔드는 여전히 React/JS코드 작성을 합니다. 다만 렌더링이 브라우저뿐 아니라 서버에서도 수행되며, 백엔드 API와 연계해 초기 HTML을 만들어내는 책임이 추가된다는 점이 다릅니다. SSR 시 프론트엔드는 여전히 React 개발하지만, 렌더링이 서버에서도 수행되고 백엔드 API를 불러와 HTML을 만들어내는 역할까지 맡습니다.
현대 웹 개발에서는 SSR과 CSR의 경계가 점점 모호해지고 있습니다. Next.js, Nuxt.js, SvelteKit 같은 프레임워크들은 두 방식의 장점을 결합한 하이브리드 렌더링을 지원하며, 페이지 단위로 CSR과 SSR을 선택적으로 적용할 수 있습니다.
최근에는 SEO와 초기 로딩 속도가 중요한 서비스(예: 전자상거래, 콘텐츠 서비스)에서는 SSR이나 하이브리드 방식을 선호하고, 실시간 데이터 갱신이나 상호작용이 중요한 서비스(예: 대시보드, 관리자 패널)에서는 CSR을 많이 활용합니다.
또한, 단순히 SSR과 CSR에 국한되지 않고, SSG(Static Site Generation), ISR(Incremental Static Regeneration) 같은 정적 생성 기법을 활용하여 성능과 비용을 최적화하는 경우도 늘고 있습니다.
결국, 하나의 정답이 존재하는 것은 아니며, 서비스의 특성, 비즈니스 목표, 인프라 환경에 따라 적절한 조합을 선택해야 합니다.