오진수 블로그
profile image

오진수

소프트웨어 개발자.

Goodvation 재직 중.

카테고리

  1. 전체 (14)
  2. 포트폴리오 (3)
  3. 프로그래밍 (11)
profile image오진수 · 프로그래밍 · 

Next.js vs Remix 비교 둘다 운영 중인 후기

Next.js에서 Remix로, Remix에서 Next.js로 다시 돌아온 과정


Frame 1 (9).png


Next.js를 사용하다가 작년 이맘때쯤 잠시 Remix로 넘어갔던 것 같습니다.

물론 아래에서 설명하겠지만 Next.js 15.5 이후로 저는 다시 Next.js를 선택하고 있습니다.

그러고 보니 지금 글을 쓰고 있는 이 Makernote도 Remix로 만들었네요.

오늘은 제가 Next.js와 Remix 모두 사용하면서 웹사이트를 운영한 경험을 중심으로 Next.js와 Remix를 비교해 보는 시간을 갖도록 하겠습니다.

Next.js와 Remix 중에 혹여 고민하는 분이 있다면 도움이 된다면 좋겠습니다.


당시 Remix로 넘어간 세 가지 이유


React 문법을 지원하는 SSR 프레임워크는 대표적으로 Next.js와 Remix가 있습니다. 제가 Next.js를 사용하다가 Remix로 넘어간 이유는 이렇습니다.


첫째로, Next.js는 개발 환경에서 빌드 속도가 너무 느렸습니다.

당시에는 개발 환경에서 Turbopack을 지원하지 않았습니다.

Webpack 기반인 Next.js보다 Vite 기반인 Remix가 개발 환경에서 훨씬 빨랐습니다.

서비스가 커지고 DB가 해외에 있는 상황에서 Next.js는 페이지 하나 컴파일하는 데에 적으면 1초 많으면 10초까지 걸렸습니다.


둘째로, Next.js가 강제하는 최적화를 위한 몇 가지 기본 기능들이 마음에 들지 않았습니다.

페이지 로드 및 fetch 함수에 캐싱이 기본적으로 들어가는 점이 오히려 기능 작동을 쉽게 예측할 수 없도록 만들었습니다.

Image 컴포넌트도 Cloludfront를 통해 Ondemand Image Resizing을 선호하는 저에게는 필요가 없으나 사용하지 않으면 경고들이 따라붙습니다.

성능 최적화를 위한 뭐랄까 과한 친절인데... 제가 Next.js를 도입한 이유는 성능 때문이 아닙니다.

저는 단지 React 문법을 사용하면서 Server Side Rendering을 지원하는 프레임워크를 원했습니다.

이 두 가지 기술이 통합되어 있기만 하면 웹사이트는 정말 쉽게 만들어집니다.


셋째로, React Server Component(RSC)를 지원하기 위해서 Next.js는 익숙하지 않은 구조를 강요했습니다.

Next.js측은 RSC가 Streaming 방식으로 로딩되기 때문에 Server Component 안에서 쿠키 설정 같은 사이드이펙트를 지원할 수 없다는 입장입니다. 그래서 해당 경로에서 쿠키를 설정하기 위해서는 middleware를 사용해야 합니다.

여기까지는 그래도 괜찮은데, 당시 middleware는 edge runtime 기반으로 설계되어서 node runtime 함수를 사용하지 못했습니다. 인증 처리와 같은 단순한 기능을 구현하는 데에도 장애물로 작용했고 HTTP 요청을 한 번 더 주고받는 등 우회로를 써야 하는 점이 불만족스러웠습니다. 이 문제에 대해서는 실제로 많은 혼란과 문제제기가 존재합니다. RSC를 지원하고자 하는 의욕과 성능 최적화 위한 과한 친절이 합쳐진 결과라고 생각합니다.


이러한 상황에서 Remix로 넘어간 이유는 단지 구조가 심플했기 때문입니다. Remix 개발자도 웹 표준을 지향한다고 이야기했고 Route handler 인터페이스를 RequestResponse로 정의했던 점도 인상깊었습니다. NextRequest 같은 게 아니라 말이죠.


저는 기술을 선택할 때 무엇보다도 제어가능성을 따집니다. 제어가능성이 존재하는 용어인지 모르겠네요. 제 말은 문제가 생겼을 때 근본적인 원인을 직접 제어할 수 있어야 (그래서 고칠 수 있어야) 한다는 뜻입니다. 예를 들어서 Next.js에서 지원하는 디렉토리 기반 라우팅은 편리하지만 어떤 면에서는 라우팅에 관련해서는 제가 제어할 수 없다는 뜻이기도 합니다. 물론 오픈소스 기여를 하거나 Folk할 수도 있지만 시간이 걸리는 일입니다. 반면 Express는 직접 라우팅 관련 코드를 제어할 수 있고 Remix도 마찬가지입니다.


이건 제가 기본적으로 라이브러리 사용을 꺼리고 저수준 기술을 최소한으로 사용하기를 선호하는 까닭입니다. 물론 기술 선택에 있어서는 다른 커다란 축인 생산성도 함께 고려해야만 하겠습니다.


Next.js 실제 운영 중인 후기


Screenshot 2025-08-28 at 12.04.17 AM.png

보시는 웹사이트는 고객님들이 네이버와 구글 등 포털에서 검색으로 주로 접속합니다. 포트폴리오를 확인하고 견적신청을 남기는 공간이죠. 고객님들이 직접 접속하기 때문에 최우선으로 고려한 부분은 페이지 로딩 시간입니다.


Next.js가 지원하는 Static Site Generation(SSG)가 빠르기는 빠릅니다. 페이지를 미리 생성해 놓고 요청시 즉각 응답하기 때문에 빠를 수밖에 없습니다. 아무리 Remix가 Dynamic Rendering 측면에서 Next.js보다 더 빠르다고 주장한다고 해도 말입니다. 물론 stale-while-revalidate로도 동일한 기능을 구현할 수 있지만 간단한 설정으로 구현할 수 있다는 점은 여전히 매력적입니다. SSG가 기본 동작이었다는 점은 불만이었지만 말입니다.


Server Action은 초기 출시되었을 때는 적극적으로 사용했습니다. 클라이언트 측에서 API가 가진 입력 및 출력 타입을 추론할 수 있다는 점에서 매우 반가웠습니다. 하지만 이제는 사용하지 않고 있습니다. Route Handler는 여전히 간단하면서 친숙한 방식입니다. 이식하기도 용이합니다. 한번 만들면 모바일 앱을 위한 API로도 활용할 수 있습니다. Server Action은 나중에 많은 사람과 협업이 필요하고 서버와 클라이언트를 오가는 비즈니스로직이 많아진다면 고려해볼 법 합니다.


React 문법과 SSR을 지원한다는 기본 조건을 바탕으로, Next.js를 사용하는 이유는 첫째 SSG 덕분에 쉽게 구현할 수 있는 빠른 로딩 속도입니다. 그리고 둘째는 Remix가 지원하지 않는 RSC입니다. RSC가 가져다주는 이점에 대해서는 아래에서 설명하겠습니다.


Remix 실제 운영 중인 후기


Screenshot 2025-08-28 at 12.04.25 AM.png

관리자페이지는 대부분 Dynamic Rendering이 필요합니다. 정적 최적화가 그다지 필요하지 않고 기본 캐시 동작이 오히려 혼란을 초래합니다. 그리고 고객님들이 이용하는 사이트가 아니라 사내 직원이 이용하는 사이트이기 때문에 조금 느려도 크게 상관 없습니다.


Remix는 React 문법과 SSR을 지원하는 최소한의 프레임워크입니다. 무언가 시작하기 매우 좋습니다. 어떤 면에서는 PHP와도 비슷합니다. Remix가 나오고 웹 프레임워크가 결국 다시 PHP로 돌아가는가 하는 반응도 본 것 같은데요. 왜냐하면 한 페이지에서 Request부터 Response까지 직관적으로 연결되기 때문입니다. 이렇게요.


export const loader = async ({ request }) => {
  const posts = await getPosts();

  return { posts }
}

export default function Page() {
  const { posts } = useLoaderData();

  return (
    <ol>
      {posts.map((post) => (
        <li key={post.id}>{post.title}</li> 
      )}  
    </ol>
  );
}


HTML을 응답해야 할 때는 이렇게 Page라는 이름을 한 React Component로 응답합니다. 만약 HTML 페이지 라우트가 아니라 API 라우트면 loader 함수면 충분합니다.


export const loader = async ({ request }) => {
  const posts = await getPosts();

  return new Response(JSON.stringify(posts), {
    headers: {
      "Content-Type": "application/json",
    },
  });
}


이렇게 두 코드를 함께 모아 놓으면 Page 함수는 마치 Response에 대한 변형으로 보입니다. 이것이 Remix가 보여주는 직관성입니다. HTML 이든 JSON을 응답하는 API든 본질적으로는 응답 요청 구조 안에 있으니까요.


Next.js 15.5로 다시 넘어온 이유, SSG와 RSC


그런데 Next.js 15.5 이후로... 위에서 꼽은 세 가지 문제는 모두 해결된 것처럼 보입니다.


1. 개발 환경에서 빌드 속도가 느린 점 → Turbopack을 이제 개발 환경에서 지원합니다.

2. 걸리적거리는 기본 최적화 기능 → 커뮤니티 문제제기로 기본 캐시 동작을 철회했습니다.

3. RSC 지원을 위한 익숙하지 않은 구조 → Middleware에서 node runtime도 허용합니다.


실제로 신규 프로젝트를 진행하면서는 Next.js를 다시 선택했고 꽤 만족스럽습니다.


Remix에서 다시 Next.js로 넘어온 이유는 SSG와 RSC를 사용하기 위함입니다. Remix는 둘다 지원하지 않습니다. SSG는 간편한 방법으로 페이지 지연 시간을 끌어올릴 수 있습니다. Middleware랑 조합하면 더 강력해집니다.


경험상 React Server Component(RSC)는 보안 및 성능에 있어 이점이 큽니다. 이러한 이점은 특정 컴포넌트를 오직 서버에서만 처리하는 데에서 옵니다. 브라우저 기능을 사용하지 않는 컴포넌트는 JS를 넘겨줄 필요도 없고 Hydration을 수행할 필요가 없습니다.


예를 들어서 몇 년치 재무제표 데이터를 렌더링해주어야 할 일이 있었는데, Remix에서는 렌더링 속도가 매우 느렸습니다. 그 이유는 Remix는 모든 컴포넌트를 Hydration하기 때문에 재무제표 데이터가 어디에 사용되었든 상관없이 일단 브라우저측으로 전송하기 때문입니다. 데이터가 클수록 응답 크기가 커지고 속도는 느려지겠죠. 실제로 응답 내용을 잘 뜯어보면 렌더링하지 않는 재무제표 정보들까지 모두 찾아볼 수 있습니다.


dd.png


바로 이렇게, loader로 내려준 모든 정보가 유저에게 보내는 응답 내용에 노출됩니다. Remix는 전체 컴포넌트에 대해 Hydration을 수행하기 위해 이 정보를 필요로 합니다. 하지만 자칫하면 보안상 위험으로 작용할 수 있고 성능 측면에서도 낭비가 됩니다.


문제가 이렇게 되면 자연스럽게 드는 생각은 "브라우저 기능에 필요한 데이터만 보낼 수는 없을까?"하는 궁금증입니다. 왜냐하면 모든 컴포넌트가 브라우저 기능을 사용하지는 않으니까요.


그래서 우리에게는 RSC가 필요합니다. RSC를 이용하면 특정한 컴포넌트에 대해서 Hydration을 수행하지 않을 수 있습니다. 정확히 말하면 Hydration이 필요한 컴포넌트(Client Component)와 필요하지 않는 컴포넌트(Server Component)를 분리할 수 있습니다.


사실 Next.js는 Hydration을 수행하지 않는 Server Component가 기본 상태입니다. Hydration을 수행하는 Client Component를 사용하기 위해서는 "use client"라는 지시어를 파일 첫머리에 달아주어야 합니다. Client Component도 Hydration을 수행하기 위해 일정한 데이터를 필요로하지만 오직 자신이 매개변수로 받는 데이터로 한정됩니다.


React + SSR + SSG + RSC 그 이후는?


오늘은 제가 Next.js에서 Remix로, Remix에서 다시 Next.js로 옮긴 경험을 중심으로 Next.js와 Remix 주요 사항을 비교해 봤습니다.


작년에는 Remix가 개발 속도, 단순성, 직관성에 있어서 더 좋은 선택지일 수 있었습니다. 하지만 Next.js가 15.5 버전 이후로 이를 모두 해결했고 SSG와 RSC까지 지원하는 덕분에 다시 선택을 받을 수 있게 되었습니다.


Next.js는 제가 보기에는 아직도 '과한 친절'을 베푸는 것처럼 보입니다만 현재로서는 가장 좋은 선택지가 아닌가 싶습니다. 앞으로는 React + SSR + SSG + RSC를 기본적으로 지원하되 다른 기능들은 별도 모듈로 제공되는 라이브러리가 나온다면 어떨까 합니다.


React + SSR + SSG + RSC만 통합되어 있다면 웹 개발하기에는 정말 충분하다고 느껴집니다. 더 안전하고 빠른 웹을 만들어줄 다음 기술은 뭘까 생각해 보는 것도 좋을 듯합니다.


Remix는 앞으로 React Router v7로 대체된다고 하고 RSC는 비표준적이기 때문에 검토중이라고 합니다. 저는 표준 비표준을 떠나서 RSC가 마음에 듭니다. React 자체가 표준을 만들어가고 있는 점도 있구요.


그럼 오늘은 이만 마치고 다음에 또 뵙겠습니다.

댓글 0

프로그래밍 카테고리 다른 글