사용자는 2.5초를 기다리지 않는다—SSR 스트리밍이 바꾸는 경험 설계

사용자는 2.5초를 기다리지 않는다—SSR 스트리밍이 바꾸는 경험 설계

첫 바이트가 16ms에 도착하는 순간, 렌더링 전략은 성능 문제가 아니라 UX 설계 문제가 된다.

SSR 스트리밍 Nuxt 4.5 LCP 최적화 Core Web Vitals Vue Suspense 서버사이드 렌더링 웹 성능
광고

서버가 HTML을 다 만들 때까지 브라우저는 아무것도 받지 못한다. 우리는 이 구조를 너무 오래 당연하게 여겼다. 사용자 입장에서 보면, 2.5초의 빈 화면과 2.5초의 로딩 스피너는 전혀 다른 경험이다. 전자는 '고장난 것 같다'는 신호이고, 후자는 '뭔가 처리 중'이라는 신호다. SSR 스트리밍은 바로 이 지점을 건드린다.

Nuxt 4.5가 실험적으로 도입한 ssrStreaming 옵션이 화제다. dev.to에 올라온 실측 결과가 꽤 인상적이다. 동일한 페이지, 동일한 컴포넌트, 동일한 2.5초 지연 조건에서 스트리밍을 켠 라우트는 첫 바이트가 16ms에 도착했다. 반면 버퍼링 라우트는 2,518ms가 지나서야 첫 바이트를 보냈다. 전송된 HTML 총량은 5.8KB로 똑같았다. 차이는 '언제 보내느냐'였다.

작동 원리는 Vue의 Suspense와 결합된다. 느린 컴포넌트를 <Suspense> 경계 안에 넣으면, Nuxt는 셸(헤더, 네비게이션, 레이아웃)을 먼저 플러시하고 느린 경계가 해소되는 대로 청크를 추가로 흘려보낸다. 스트리밍 라우트의 응답은 14개 청크로 나뉘었고, 버퍼링 라우트는 단 1개 청크였다. 브라우저가 일찍 받은 HTML로 레이아웃을 그리는 동안 서버는 나머지를 조용히 마저 렌더링한다.

여기서 UX 관점의 핵심 질문이 생긴다. "무엇을 먼저 보낼 것인가?" 스트리밍의 가치는 빠른 첫 바이트 자체가 아니라, 그 첫 바이트에 사용자가 즉시 활용할 수 있는 내용이 담겨 있는가에 달려 있다. 빈 <div> 하나를 16ms에 보내봤자 체감 성능은 달라지지 않는다. 네비게이션, 페이지 컨텍스트, 의미 있는 로딩 상태—이것들이 셸에 포함돼 있을 때 비로소 LCP가 실질적으로 개선된다.

이 패러다임은 React 생태계에서 먼저 익숙해진 개념이다. React Server Components와 Next.js의 Suspense 기반 스트리밍이 보여준 방향을 Vue/Nuxt가 자신들의 방식으로 수렴하고 있다. 프레임워크가 달라도 해결하려는 문제는 같다. 느린 데이터 소스 때문에 전체 렌더링이 막히는 상황을, 경계를 나눠서 병렬로 처리하는 것이다. '서버 스트리밍 렌더링'은 특정 프레임워크의 기능이 아니라 현대 웹의 렌더링 패턴으로 자리잡아가고 있다.

다만 스트리밍을 켜기 전에 설계해야 할 것들이 있다. HTTP 응답이 한 번 커밋되면 이후에 상태 코드나 헤더, 쿠키를 바꿀 수 없다. 셸이 먼저 나간 뒤에 인증 리다이렉트가 필요하다면—그건 이미 늦은 것이다. Nuxt는 이 제약을 인지하고 크롤러, 캐시된 라우트, ISR/SWR, 리다이렉트 등에서는 자동으로 버퍼링으로 폴백한다. 개발자가 설계해야 할 몫은, 어떤 라우트에서 셸이 '유용한가'를 판단하는 일이다.

콘텐츠가 무거운 페이지 중 느린 API 경계가 하나 있고, 그 외 셸은 즉시 보여줄 수 있는 구조—여기서 스트리밍의 효과가 가장 극적이다. 반대로 페이지 전체가 단일 데이터 소스에 의존하거나, 응답 헤더를 동적으로 결정해야 하는 라우트라면 버퍼링이 여전히 맞는 선택이다. 성능 최적화는 언제나 트레이드오프이고, 스트리밍도 예외가 아니다.

Core Web Vitals 관점에서 보면, 스트리밍이 직접적으로 영향을 주는 지표는 LCP와 TTFB다. 실측에서 2초 이상 LCP가 줄었다는 결과는 단순한 수치 개선이 아니다. 사용자가 페이지를 '쓸 수 있다'고 느끼는 시점이 2초 앞당겨진다는 뜻이다. 그리고 그 2초는 이탈률과 전환율에 직접 연결된다. 렌더링 전략을 결정하는 일이 곧 사용자 경험을 설계하는 일이다.

출처

더 많은 AI 트렌드를 Seedora 앱에서 확인하세요