🌐 웹개발

SSR

Server-Side Rendering

서버에서 HTML을 생성하여 전송하는 렌더링 방식. SEO에 유리. Next.js, Nuxt.js가 대표적.

📖 상세 설명

SSR(Server-Side Rendering)은 사용자가 페이지를 요청할 때마다 서버에서 HTML을 동적으로 생성하여 전송하는 렌더링 방식입니다. 클라이언트는 이미 콘텐츠가 포함된 완성된 HTML을 받기 때문에, 초기 로딩 시 화면이 빠르게 표시됩니다.

SSR의 가장 큰 장점은 SEO와 소셜 미디어 공유입니다. 검색 엔진 크롤러나 SNS 봇이 JavaScript 실행 없이도 페이지 콘텐츠를 읽을 수 있어, SPA의 SEO 문제를 해결합니다. 메타 태그도 동적으로 생성할 수 있습니다.

Next.js의 getServerSideProps, Nuxt의 asyncData, Remix의 loader 등이 SSR을 구현합니다. 서버에서 데이터를 가져와 HTML에 포함시킨 후, 클라이언트에서 Hydration을 통해 React/Vue 앱으로 활성화됩니다.

SSR은 서버 부하가 증가하고 TTFB(Time To First Byte)가 SSG보다 느립니다. 하지만 실시간 데이터가 필요하거나 사용자별 맞춤 콘텐츠를 제공해야 할 때 필수적인 방식입니다. Streaming SSR로 응답 시간을 개선할 수 있습니다.

💻 코드 예제

// Next.js SSR with getServerSideProps
// pages/dashboard.tsx

import { GetServerSideProps } from 'next';
import { getServerSession } from 'next-auth';
import { authOptions } from './api/auth/[...nextauth]';

interface DashboardProps {
  user: { name: string; email: string };
  stats: { visitors: number; revenue: number };
}

// 매 요청마다 서버에서 실행
export const getServerSideProps: GetServerSideProps = async (context) => {
  // 인증 확인
  const session = await getServerSession(context.req, context.res, authOptions);

  if (!session) {
    return {
      redirect: {
        destination: '/login',
        permanent: false,
      },
    };
  }

  // 실시간 데이터 페칭
  const [user, stats] = await Promise.all([
    fetch(`${process.env.API_URL}/user/${session.user.id}`).then(r => r.json()),
    fetch(`${process.env.API_URL}/stats`, {
      headers: { Authorization: `Bearer ${session.accessToken}` }
    }).then(r => r.json())
  ]);

  return {
    props: {
      user,
      stats,
    },
  };
};

export default function Dashboard({ user, stats }: DashboardProps) {
  return (
    <div>
      <h1>안녕하세요, {user.name}님</h1>
      <div className="stats">
        <div>방문자: {stats.visitors.toLocaleString()}</div>
        <div>매출: ₩{stats.revenue.toLocaleString()}</div>
      </div>
    </div>
  );
}

// Next.js App Router SSR
// app/dashboard/page.tsx
async function Dashboard() {
  const session = await getServerSession();
  const stats = await fetch('https://api.example.com/stats', {
    cache: 'no-store' // SSR 강제
  }).then(r => r.json());

  return <DashboardClient stats={stats} />;
}

🗣️ 실무 대화 예시

기술 미팅에서:

"대시보드 페이지는 SSR이 맞아요. 실시간 데이터에 인증도 필요하니까요. 근데 서버 부하 걱정되면 캐싱 레이어 추가하거나 stale-while-revalidate 헤더 설정하면 됩니다."

기술 면접에서:

"SSR의 단점과 해결 방법은요?" - "TTFB가 느려질 수 있는데, Streaming SSR로 점진적 렌더링하거나, Edge Runtime에서 실행해서 지연 시간을 줄일 수 있습니다."

코드 리뷰에서:

"getServerSideProps에서 5개 API 순차 호출하고 있네요. Promise.all로 병렬화하면 응답 시간 반 이상 줄일 수 있어요. 의존성 없는 요청은 동시에 보내세요."

⚠️ 주의사항

🔗 관련 용어

SSG Hydration Streaming SSR Next.js Edge Runtime

📚 더 배우기

📄 Next.js 공식 문서 - Server-side Rendering 📄 Nuxt 공식 문서 - Server-side Rendering 📄 web.dev - Rendering on the Web