개발 slecs

Astro SSR 전환 후 동적 라우트 쿼리 파싱 오류 수정

목차

[...slug].astro 파일 한 곳을 건드렸는데, 생각보다 근본적인 문제였다.

뭐가 문제였나

Astro를 output: 'server' 모드로 세팅하면 모든 페이지가 기본적으로 SSR로 동작한다. 그런데 [...slug].astro 같은 동적 라우트에서 쿼리 파라미터를 읽는 방식이 output: 'static'이나 하이브리드 모드랑 미묘하게 달라서, 빌드는 통과하는데 런타임에서 undefined가 튀어나오거나 쿼리가 아예 반영이 안 되는 상황이 생긴다.

기존 코드가 아마 이런 패턴이었을 거다.

---
//  정적 빌드 가정 패턴 - SSR 에서 쿼리를 제대로  읽음
const { slug } = Astro.params;
const query = Astro.url.searchParams.get('page'); // SSR 에선 OK 이지만
// 혹은 props 기반으로만 처리하거나, getStaticPaths 잔재가 남아있는 경우
---

output: 'server'에서는 getStaticPaths가 사라지고, 매 요청마다 서버에서 라우트를 처리한다. 이 말은 쿼리 파라미터도 빌드 타임이 아닌 요청 타임에 읽어야 한다는 뜻이다. SSR 호환 패턴으로 바꾸면 아래처럼 된다.

---
//  output: 'server' 호환 패턴
const { slug } = Astro.params;
const url = new URL(Astro.request.url);
const page = url.searchParams.get('page') ?? '1';
// 또는
const page = Astro.url.searchParams.get('page') ?? '1';
---

Astro.url은 SSR에서도 잘 동작하는 편이지만, getStaticPaths 잔재나 Astro.props로 쿼리를 끌어쓰는 패턴이 섞여있으면 조용히 깨진다.

[...slug] 패턴 특성

catch-all 라우트([...slug])는 단일 파라미터 라우트보다 처리해야 할 경우의 수가 더 많다.

라우트 패턴 Astro.params 형태 slug가 없는 경우
[slug].astro { slug: 'foo' } 라우트 미매칭
[...slug].astro { slug: 'foo/bar' } { slug: undefined }

slugundefined일 수 있다는 점, 그리고 /로 이어진 경로가 통째로 문자열로 들어온다는 점 때문에 파싱 로직이 조금 더 방어적으로 작성되어야 한다. 여기에 동적 쿼리까지 더해지면 — 예를 들어 /posts/2026/05처럼 slug로 날짜 필터를 받으면서 동시에 ?page=2 같은 페이지네이션 쿼리도 받는 구조라면 — slug 파싱과 쿼리 파싱이 혼재해서 버그가 숨기 좋은 구조가 된다.

회고

솔직히 이 버그는 output: 'static'output: 'server'로 전환할 때 같이 잡혔어야 했다. SSR 전환은 단순히 config 한 줄 바꾸는 게 아니라, 빌드 타임 가정을 런타임 가정으로 전환하는 작업이라 동적 라우트 전체를 훑어봤어야 했다.

팀에 Astro 처음 쓰는 사람이 있으면 꼭 짚어주는 포인트가 있다.

  • getStaticPathsoutput: 'server'에서 쓰면 빌드 에러가 아니라 그냥 무시되거나 경고만 뜨는 경우가 있음 → 조용히 동작이 바뀜
  • Astro.request는 SSR에서만 온전히 존재 → 하이브리드 모드에서 prerender 페이지에서 쓰면 런타임 에러
  • 쿼리 파라미터는 항상 null 가능성을 열어두고 기본값 처리할 것

[...slug].astro 파일 하나였지만, SSR 전환 이후 동적 라우트가 제대로 동작하는지 검증하는 계기가 됐다. 다음 Astro 프로젝트에서 SSR로 시작한다면 처음부터 output: 'server' 기준으로 쿼리 패턴을 잡을 것.


끝.


🛒 이 글과 어울리는 추천 상품

*위 링크는 쿠팡파트너스 활동의 일환이며, 일정액의 수수료를 제공받을 수 있습니다.

댓글 0

첫 댓글 달아줘.