Next.js 요청이 Server Component에 닿기까지의 경로
브라우저 주소창에 URL을 치면 Next.js의 Server Component가 실행되기까지 무슨 일이 벌어지는지 순서대로 짚어봤다.
브라우저의 요청은 Next.js 서버로 곧장 가지 않는다
https://example.com/users를 열면 브라우저가 바로 "Next.js 서버"를 찾아가는 게 아니다. 도메인을 DNS로 조회해 IP 주소를 얻고, 그 주소로 HTTPS 요청을 보낸다. 그 요청을 실제로 먼저 받는 쪽은 CDN이나 로드 밸런서, 리버스 프록시일 수 있다.
작은 서비스라면 훨씬 단순하다. 브라우저에서 Next.js 서버로 바로 이어지기도 하고, Nginx 하나만 앞에 두기도 한다.
Next.js 서버 자체가 웹 서버일 수 있다
"Web Server"라는 표현은 문맥에 따라 의미가 다르다. Nginx나 Apache처럼 HTTP 요청을 받고 전달하는 서버를 가리키기도 하고, 넓은 의미로 웹 요청을 처리하는 서버 자체를 가리키기도 한다.
Next.js도 HTTP 요청을 받아 응답할 수 있으니 Next.js 서버 자체가 웹 서버 역할을 할 수 있다. 앞에 별도의 웹 서버를 두고 Next.js로 넘기는 구조여야만 하는 건 아니었다.
Nginx, CDN, Load Balancer는 왜 필요한가?
서비스가 커지면 Next.js 서버 하나만 직접 노출하는 대신 앞단에 여러 계층을 둘 수 있다.
CDN은 사용자와 가까운 Edge(사용자 근처에 배치된 CDN 서버)에서 정적 리소스 등을 캐싱해 전달한다. 원본 서버까지 매번 요청하지 않아도 되는 콘텐츠를 가까운 곳에서 돌려줄 수 있다. 로드 밸런서는 그 아래에서 요청을 여러 Next.js 인스턴스로 나눈다. Nginx 같은 리버스 프록시를 로드 밸런서와 Next.js 사이에 두기도 한다. 외부 요청을 받아 내부 서버로 전달하는 역할이다.
이 계층들은 Next.js의 필수 구성요소가 아니다.
GET 요청은 Route 매칭을 거쳐 처리 방식이 정해진다
브라우저가 GET /users를 보내면, Next.js는 요청을 받아 어떤 Route와 매칭되는지 확인하고 그 Route의 처리 방식을 정한다. 렌더링일 수도 있고 API 응답이나 정적 리소스일 수도 있다. UI 페이지라면 app/users/page.tsx가 매칭돼 React Server Components가 처리되고, HTML과 RSC 관련 데이터가 브라우저로 간다.
여기까지는 개념적인 흐름이다. Next.js 내부가 실제로 이 단계들을 단순한 순서대로 하나씩 실행하는 건 아니다.
Next.js는 어떻게 /users와 app/users/page.tsx를 연결할까?
App Router는 파일 시스템 기반 라우팅을 쓴다.
app/
├── page.tsx
├── users/
│ └── page.tsx
└── products/
└── page.tsx이 구조에서 만들어지는 Route는 이렇다.
/ → app/page.tsx
/users → app/users/page.tsx
/products → app/products/page.tsx그러면 요청이 들어올 때마다 app 폴더를 열고, users 폴더를 열고, page.tsx를 찾는 탐색이 매번 벌어지는 걸까. 그렇지 않았다. 빌드 과정에서 파일 구조를 분석해 Route 정보를 만들어두고, 런타임에서는 그 정보로 요청 URL을 Route와 매칭한다.
모든 요청에서 Server Component가 실행되는 것은 아니다
Next.js의 모든 요청이 Server Component를 실행한다는 건 오해였다.
GET /users는 UI Route라서 Server Component가 관여한다. 반면 GET /api/users는 Route Handler가 처리한다. Route Handler는 app/api/.../route.ts에서 GET·POST 같은 함수를 export해 JSON 등을 돌려주는 엔드포인트다.
app/
├── users/
│ └── page.tsx
│
└── api/
└── users/
└── route.ts같은 users 리소스를 가리켜도 매칭되는 Route에 따라 실행되는 코드가 갈라진다.
Next.js 요청을 볼 때는 어떤 Route가 매칭되고 그 Route에서 어떤 코드가 실행되는지가 먼저다.
Proxy는 headers·redirects 다음, Route 매칭 앞에서 실행된다
Proxy는 라우트가 렌더링되기 전에 요청을 검사하거나 변경하는 계층이다. Next.js 16에서 middleware.ts가 proxy.ts로 바뀌었고, 내보내는 함수 이름도 middleware에서 proxy가 됐다. Express.js의 middleware와 혼동을 부른다는 이유로 이름이 바뀌었다.
공식 실행 순서는 8단계고 Proxy는 그중 세 번째다. next.config.js의 headers와 redirects가 먼저 적용되고, Proxy 다음에 파일 시스템 라우트 매칭이 이어진다.
여기서 처리하는 건 인증 검사, 권한 검사, Redirect, Rewrite(URL은 그대로 두고 내부에서 다른 경로로 처리), Request Header 처리, 특정 경로에 대한 공통 처리 같은 것들이다. 로그인하지 않은 사용자가 /users에 접근하면 Proxy에서 로그인 여부를 확인하고 /login으로 Redirect하는 식이다.
용어를 정확히 구분하면 Proxy는 "Proxy를 실행한다", Routing은 "Route를 매칭한다 / 라우팅한다"라고 쓰는 게 자연스럽다.
Proxy는 비즈니스 로직 계층이 아니다
Proxy는 요청을 빠르게 검사하고 다음 단계로 넘기는 계층에 가깝다. 인증 검사, 권한 검사, Redirect, Rewrite처럼 판단이 짧게 끝나는 작업이 여기에 맞는다.
복잡한 비즈니스 로직은 Server Action이나 Route Handler, 그 아래의 Service·Repository 계층(비즈니스 로직과 DB 접근을 담당하는 서버 쪽 계층)에서 처리하는 편이 낫다.