아일랜드 아키텍처, 결국 무엇을 줄이는 구조인가?

정적 HTML을 기본으로 깔고, 상호작용이 필요한 조각만 독립된 "섬"으로 하이드레이션하는 구조다. 페이지 전체를 하나의 앱으로 띄우지 않기 때문에 초기에 보내는 JavaScript 양이 줄어드는 게 핵심 전제지만, 섬을 어떻게 나누고 언제 깨우느냐에 따라 효과가 크게 갈린다. 숫자로 보기 전에 먼저 "이 화면이 왜 하나의 앱일 필요가 없는가"부터 따져야 한다.

  • 아일랜드 구조는 콘텐츠 영역은 정적 HTML, 인터랙션 영역만 클라이언트 JS로 분리하는 전략이다
  • 하이드레이션 시점은 client:load, client:idle, client:visible 같은 지시어로 직접 통제한다Astro 공식 소개
  • React Server Components도 서버 실행 컴포넌트는 JS를 보내지 않는다는 점에서 유사한 분할 전략으로 볼 수 있다reactperf.dev
  • 섬을 잘게 나눠도 공통 의존성이 중복되면 절감 효과가 상쇄될 수 있다
  • 2026년 기준 이 전략은 SSG/ISR/SSR과 배타적이지 않고 셸 위에 얹는 보완재로 쓰이는 경우가 많다

판교에서 콘텐츠 중심 사이트를 운영하며 느낀 건, "전체를 React로 띄울까 말까"보다 "이 페이지에서 실제로 움직여야 하는 부분이 몇 퍼센트인가"를 먼저 재는 게 판단을 쉽게 만든다는 점이다. 블로그 상세 페이지에서 실제로 상호작용이 필요한 건 댓글 폼과 공유 버튼 정도였는데, 처음엔 그 둘 때문에 페이지 전체를 React 앱으로 하이드레이션하고 있었다.

정적 HTML 위에서 어떻게 일부만 살아나는가?

빌드 시점에 전체 페이지를 HTML로 찍어내고, 인터랙티브 컴포넌트에만 하이드레이션 지시어를 붙이는 방식으로 동작한다. Astro는 기본적으로 JavaScript를 전송하지 않고, 댓글 폼·검색창·장바구니처럼 명시적으로 지정한 컴포넌트만 클라이언트로 보낸다Astro 소개 자료. client:load는 페이지 로드 즉시, client:idle은 브라우저가 한가해질 때, client:visible은 뷰포트에 들어올 때 하이드레이션한다. 흥미로운 건 이 셋을 같은 페이지 안에서 React·Vue·Svelte처럼 다른 프레임워크 컴포넌트로 섞어 써도 된다는 점이다. 실무에서는 "이 컴포넌트가 화면에 보이자마자 눌릴 가능성이 있는가"를 기준으로 지시어를 고르는데, 접힘 영역 아래 있는 댓글 폼을 client:load로 박아두면 사용자가 스크롤도 하기 전에 JS를 실행하는 낭비가 생긴다. 반대로 결제 버튼처럼 즉시 반응해야 하는 요소를 client:visible로 늦추면 클릭 시점에 하이드레이션이 끝나지 않아 입력이 씹히는 경험을 만들 수 있다. 이 선택은 결국 "화면에 보이는 즉시 필요한가, 지연 가능한가"라는 질문 하나로 갈린다.

서버 컴포넌트와 아일랜드는 뭐가 다른가?

둘 다 "필요한 부분만 클라이언트로 보낸다"는 목표는 같지만, 경계를 긋는 단위가 다르다. 아일랜드는 페이지 빌드 시점에 정적 HTML과 클라이언트 컴포넌트를 분리하는 반면, React Server Components는 서버에서 실행되는 컴포넌트 트리 안에 클라이언트 컴포넌트 경계를 중첩시키는 구조다. 한 자료는 상품 카드 50개와 버튼 하나가 있는 페이지에서 RSC 경계를 제대로 그으면 전송 JS가 72KB에서 약 5KB로 줄어든다고 설명한다reactperf.dev. 다만 이건 프레임워크 기본값이 아니라 컴포넌트 의존성 구성을 전제로 한 사례 수치라는 점은 분명히 해둘 필요가 있다. 서버 컴포넌트는 DB·파일시스템에 직접 접근할 수 있어 브라우저의 추가 API 왕복을 줄이지만, 요청마다 서버 렌더링이 일어나면 캐시 설정과 서버 CPU·메모리가 중요한 변수로 떠오른다. 즉 "JS가 줄었다"가 자동으로 "전체 비용이 줄었다"를 뜻하지 않는다는 점이 RSC와 순수 아일랜드 구조의 가장 큰 차이다. 한 엔터프라이즈 대시보드 마이그레이션 사례는 클라이언트 중심 React에서 RSC로 바꾼 뒤 LCP가 2.8초에서 0.9초, 전송 JS가 420KB에서 180KB로 줄었다고 보고했지만team400.ai, 버전·하드웨어·네트워크 조건이 공개되지 않아 재현 가능한 벤치마크로 쓰기엔 근거가 제한적이라는 점도 같이 기록해둔다.

아일랜드로 나누면 실제로 JS가 얼마나 줄어드는가?

동일 조건이 아니면 수치를 그대로 믿기 어렵지만, 공개된 비교 자료 하나는 참고할 만한 격차를 보여준다. 한 프레임워크 비교에서 Qwik은 중앙값 TTI 1.1초·TBT 30ms·전송 JS 12KB, Astro는 1.4초·70ms·34KB, Next.js App Router는 2.3초·210ms·96KB로 측정됐다islands-architecture.com 벤치마크. 다만 이 결과는 테스트 장비·페이지 구성·네트워크 조건에 크게 의존하므로 제품 일반 성능으로 단정할 근거는 아니다. 측정 항목이 TTI, TBT, INP, 전송 JS로 구성된 것도 눈여겨볼 부분인데, 단순 Lighthouse 점수 하나만 보고 "이 프레임워크가 낫다"고 결론 내리면 실제 상호작용 지연을 놓치기 쉽다. 번들 크기 쪽도 조건이 중요하다. Next.js 비교 글은 동일한 시작 UI에서 비압축 JS 페이로드를 Next.js 566KB, Remix 371KB로 측정했는데strapi.io, 압축 여부와 측정 범위가 명확하지 않아 실제 서비스에서는 gzip·Brotli 전송량과 라우트별 번들 분석을 따로 돌려봐야 한다. 내가 운영 중인 프로젝트에서도 Lighthouse 점수만 보고 넘어갔다가 실제 모바일 중저가 기기에서 TBT가 체감상 훨씬 크게 느껴진 경험이 있어서, 지금은 전송 JS와 TBT를 같이 기록하는 쪽으로 바꿨다.

아일랜드 = 무조건 JS가 적다는 말이 맞을까?

틀린 전제다. 인터랙티브 컴포넌트를 잘게 쪼개도 각 섬이 같은 UI 라이브러리와 공통 의존성을 중복으로 들고 있으면 절감 효과가 희석된다islands-architecture.com. 예를 들어 React 기반 아일랜드를 세 개 배치했는데 각각 별도 번들로 React 런타임을 포함하면, 하나의 React 앱보다 총 전송량이 더 클 수도 있다. 또 다른 흔한 함정은 client:load를 습관적으로 붙이는 것이다. 지연 가능한 컴포넌트까지 즉시 하이드레이션하면 정적 HTML 위에 사실상 전체 앱을 바로 띄우는 구조가 되어, 아일랜드를 도입한 의미가 줄어든다. 나는 초기 마이그레이션 때 댓글 폼·공유 버튼·관련 글 추천까지 전부 client:load로 박아두고 "아일랜드로 바꿨는데 왜 체감 차이가 없지"라고 한참 헤맸는데, 원인은 구조가 아니라 지시어 선택이었다. 화면에 보이는 즉시 눌릴 가능성이 있는 것과, 스크롤 이후에나 쓰이는 것을 구분하는 작업이 아일랜드 도입의 절반 이상을 차지한다고 봐도 된다.

그래서 언제 쓰고 언제 피해야 하나?

콘텐츠가 자주 바뀌지 않고 개인화가 거의 없는 블로그·문서·마케팅 페이지는 SSG로 빌드 시 HTML을 만들어 CDN에서 서빙하는 쪽이 기본값이다web-tutorial.com. 여기에 댓글·검색·공유 같은 작은 인터랙션만 아일랜드로 얹으면 서버 연산 비용을 늘리지 않고도 상호작용을 확보할 수 있다. 상품 목록처럼 일정 주기로 갱신되지만 매 요청마다 최신 데이터가 필요하지 않은 화면은 ISR로 구분하는데, 60초 단위로 재생성하는 방식이 사례로 제시된다web-tutorial.com. 반대로 사용자별 대시보드, 권한에 따른 데이터, 요청 시점의 재고·가격처럼 개인화나 강한 최신성이 필요하면 SSR이 자연스러운데, 이 경우 요청마다 DB 조회와 렌더링이 발생하므로 서버 CPU와 캐시 적중률을 따로 측정해야 한다. 로그인 이후 상호작용이 중심이고 SEO 비중이 낮은 화면은 CSR이나 SSR/SSG 셸 위에 CSR 인터랙션을 얹는 구성이 적합하지만, 초기 JS 다운로드·파싱과 API 왕복이 초기 표시를 늦출 수 있다는 점은 감수해야 한다. 실무에서는 이 네 가지를 섞는 게 일반적이다. 공개 콘텐츠는 SSG/ISR, 개인화 영역은 SSR, 댓글·필터·장바구니는 CSR/아일랜드로 나누는 조합이 Next.js 비교 자료에서도 소개된다strapi.io. 반대로 페이지 전체가 로그인 후 복잡한 상태 관리로 가득 차 있고 SEO가 거의 필요 없다면, 아일랜드로 잘게 쪼개는 것보다 하나의 클라이언트 앱으로 통합하는 편이 의존성 중복을 줄이는 데 더 낫다.

결국 판단 기준은 무엇으로 요약되나?

세 가지 질문을 순서대로 던지는 흐름이 재현하기 쉽다. 먼저 "얼마나 자주 바뀌는가"로 SSG·ISR·SSR을 나누고, 다음 "사용자마다 다른가"로 캐시 가능 여부를 판단하고, 마지막 "어디까지 상호작용이 필요한가"로 CSR·아일랜드·서버 컴포넌트 경계를 정한다. 측정할 때는 TTI·TBT·INP·전송 JS를 함께 기록하고, 프레임워크·런타임 버전, 빌드 모드, CDN 사용 여부, 캐시 적중 여부, 네트워크 프로파일, 측정 횟수와 p75까지 남겨야 다음에 재현할 수 있다islands-architecture.com. 조건이 불완전한 공개 벤치마크는 결론이 아니라 참고 사례로만 쓰는 게 안전하다.

핵심 정리

  • 아일랜드 아키텍처는 정적 HTML을 기본으로 하고 인터랙션 컴포넌트만 선택적으로 하이드레이션하는 전략이며, 하이드레이션 시점 제어가 효과의 절반을 좌우한다
  • RSC도 서버 실행 컴포넌트의 JS를 보내지 않는다는 점에서 유사하지만, 경계 단위와 서버 비용 구조가 다르다
  • 비교 벤치마크(Qwik 1.1s/12KB, Astro 1.4s/34KB, Next.js 2.3s/96KB)는 특정 조건에서의 사례이지 일반 성능 보장이 아니다
  • client:load 남발과 아일랜드 간 의존성 중복은 아일랜드 구조의 가장 흔한 실패 모드다
  • 콘텐츠 갱신 주기와 개인화 정도로 먼저 SSG·ISR·SSR을 나누고, 그 위에 상호작용 단위로 CSR·아일랜드 경계를 얹는 순서가 판단을 쉽게 만든다