Expo

Expo Router 사용법: app 폴더와 Stack Tabs 구조 잡기

2026.04.22·수정 2026.05.11·약 13분

이 글에서 정리하는 내용

Expo Router를 처음 볼 때 가장 헷갈리는 src/app 폴더 규칙, 파일 이름 표기법, _layout.tsx, Stack, Tabs, 화면 이동, URL 파라미터, 인증 보호 흐름까지 한 번에 정리합니다. 글을 끝까지 읽으면 폴더 구조를 보고 어떤 경로가 열리고 어떤 네비게이션이 만들어지는지 스스로 해석할 수 있는 수준을 목표로 합니다.

Expo Router를 먼저 어떻게 이해하면 좋은가

Expo Router 사용법: app 폴더와 Stack Tabs 구조 잡기 핵심 개념을 설명하는 첫 번째 본문 이미지

Expo Router는 React Native와 web에서 함께 쓸 수 있는 파일 기반 라우터입니다. 핵심은 화면 이름을 따로 한곳에 길게 등록하는 방식보다, src/app 안의 파일과 폴더 구조를 그대로 경로와 네비게이션 관계로 해석한다는 점입니다. 그래서 Expo Router를 처음 공부할 때는 API를 많이 외우기보다, 파일 이름이 어떤 URL이 되고 어떤 레이아웃 안에 들어가는지부터 이해하는 편이 훨씬 안정적입니다.

또 Expo Router는 React Navigation 위에서 동작합니다. 완전히 새로운 이동 시스템이라기보다, Stack, Tabs, Drawer 같은 개념을 파일 구조와 결합해서 더 읽기 쉽게 만든 방식에 가깝습니다. 이 관점을 잡아두면 왜 _layout.tsx가 중요한지, 왜 route group이 필요한지, 왜 페이지 파일과 일반 컴포넌트 파일을 분리해야 하는지 한 흐름으로 이해됩니다.

가장 작은 구조부터 읽기

// src/app 안의 파일이 곧 라우트가 됩니다.
// index.tsx 는 기본 경로 / 를 의미합니다.
// about.tsx 는 /about, profile.tsx 는 /profile 을 의미합니다.
src/ app/ index.tsx about.tsx profile.tsx

위 구조라면 앱의 시작 화면은 index.tsx가 되고, about.tsx는 /about, profile.tsx는 /profile이 됩니다. Expo Router는 이처럼 화면 연결의 출발점이 코드 호출보다 파일 배치에 있기 때문에, 프로젝트를 처음 열었을 때도 구조를 빠르게 따라가기 좋습니다.

src/app 폴더와 파일 이름 표기법

Expo Router에서는 src/app 디렉터리가 라우트 전용 영역입니다. 여기 들어간 파일은 페이지나 레이아웃으로 취급되므로, 테스트 파일이나 공용 유틸 함수, 재사용 UI 컴포넌트를 함께 넣으면 구조가 금방 흐려집니다. 공용 코드는 src/components, src/hooks, src/features 같은 별도 위치로 빼고, src/app에는 화면 파일만 두는 편이 좋습니다.

파일 이름의 의미도 명확합니다. index.tsx는 해당 폴더의 기본 경로이고, [id].tsx는 동적 세그먼트이며, (tabs)처럼 괄호로 감싼 폴더는 route group이라서 URL에 직접 나타나지 않습니다. 여기에 더해 + 같은 + 파일은 특수 역할을 가지며, 잘못된 경로 처리나 web HTML 보일러플레이트, native intent, middleware 같은 용도로 사용됩니다.

정적 라우트, 동적 라우트, 그룹 폴더, 특수 파일 예시

// [id].tsx 는 동적 파라미터를 받습니다.
// (tabs) 는 구조용 그룹이라 URL 조각에 포함되지 않습니다.
// +not-found.tsx 는 없는 경로를 처리하는 특수 파일입니다.
src/ app/ index.tsx settings.tsx post/ [id].tsx (tabs)/ index.tsx my.tsx +not-found.tsx

이 구조에서 settings.tsx는 /settings, post/[id].tsx는 /post/1 같은 경로와 연결됩니다. 반면 (tabs)는 구조를 묶기 위한 이름이라서 /(tabs)/my 같은 주소가 생기지 않습니다. 그리고 +는 존재하지 않는 경로로 진입했을 때 보여줄 화면을 정의할 때 사용합니다.

표기 의미
index.tsx / [id].tsx 기본 경로 / 동적 파라미터
(tabs) / + 구조용 그룹 / 특수 라우트 파일

_layout.tsx와 Stack, Tabs 구조

Expo Router에서 가장 중요한 파일은 _layout.tsx입니다. 이 파일은 페이지가 아니라같은 디렉터리 아래 라우트들이 어떤 네비게이터 안에서 움직일지 정의하는 구조 파일입니다. 루트 _layout.tsx는 다른 어떤 화면보다 먼저 렌더링되며, 예전 App.tsx에 넣던 폰트 로드, provider 연결, splash 제어 같은 초기화 코드를 두는 위치가 됩니다.

실무에서는 보통 루트 _layout.tsx에서 전체 Stack을 잡고, 하위 route group 내부 _layout.tsx에서 Tabs를 나누는 흐름을 많이 씁니다. 이렇게 하면 탭 내부 화면과 탭 바깥 상세 화면을 분리해서 읽기 쉬워지고로그인 전용 화면이나 모달 화면도 어느 스택에 속하는지 구조적으로 파악하기 쉬워집니다.

루트 Stack과 탭 레이아웃 나누기

// src/app/_layout.tsx
// 앱 전체의 기본 Stack 구조를 정의합니다.
import { Stack } from 'expo-router'; export default function RootLayout() { return <Stack screenOptions={{ headerShown: false }} />;
} // src/app/(tabs)/_layout.tsx
// 탭 내부 화면들을 Tabs 안에 배치합니다.
import { Tabs } from 'expo-router'; export default function TabsLayout() { return ( <Tabs> <Tabs.Screen name="index" options={{ title: '홈' }} /> <Tabs.Screen name="my" options={{ title: '마이' }} /> </Tabs> );
}

여기서 중요한 포인트는 Stack과 Tabs를 코드로 선언하더라도, 어떤 화면이 그 안에 들어가는지는 파일 위치가 함께 결정한다는 점입니다. 즉 Expo Router는 네비게이터를 없애는 도구가 아니라, 네비게이터와 파일 구조를 자연스럽게 묶어주는 도구라고 보는 편이 정확합니다.

화면 이동, 파라미터, 인증 보호 흐름

Expo Router 사용법: app 폴더와 Stack Tabs 구조 잡기 적용 흐름을 설명하는 두 번째 본문 이미지

Expo Router에서 이동 방식은 선언형과 명령형으로 나눠서 이해하면 편합니다. 링크처럼 UI 자체가 이동 역할을 하는 경우는 Link가 가장 자연스럽고, 버튼 클릭 뒤 조건에 따라 이동시키는 경우는 또는 router 객체를 사용합니다. 현재 문서 기준으로 일반적인 이동에서는 router.navigate를 우선 생각하면 되고, 새 화면을 스택에 명시적으로 더 쌓고 싶을 때 router.push, 현재 화면을 교체하고 싶을 때 router.replace를 보면 됩니다.

URL 파라미터도 함께 봐야 실무 흐름이 완성됩니다. 동적 세그먼트 값이나 쿼리 값은 useLocalSearchParams로 읽을 수 있고같은 화면 안에서 쿼리만 바꾸고 싶다면 router.setParams를 사용할 수 있습니다. 즉 Expo Router는 단순 화면 전환뿐 아니라, URL을 상태처럼 다루는 방식까지 자연스럽게 연결됩니다.

이동과 파라미터 처리 예시

// Link 는 선언형 이동에 적합합니다.
// router.navigate 는 일반 이동에 자주 사용합니다.
// useLocalSearchParams 로 동적 값과 쿼리 값을 읽을 수 있습니다.
import { Link, useLocalSearchParams, useRouter } from 'expo-router';
import { Button, Text, View } from 'react-native'; export default function UserScreen() { const router = useRouter(); const { id, limit } = useLocalSearchParams(); return ( <View> <Text>id: {id}</Text> <Text>limit: {limit}</Text> <Link href="/user/bacon?limit=20">유저 보기</Link> <Button title="더 보기" onPress={() => router.setParams({ limit: 50 })} /> <Button title="프로필 이동" onPress={() => router.navigate('/profile')} /> </View> );
}

인증은 한 단계 더 구분해서 봐야 합니다. 화면 안에서 조건을 보고 즉시 다른 곳으로 보내는 것은 Redirect 컴포넌트로 처리할 수 있습니다. 반면 현재 Expo Router 문서에서는 접근 제어를 더 구조적으로 처리하는 방법으로 protected routes를 안내하며, Stack.Protected나 Tabs.Protected로 특정 화면 묶음을 guard 조건에 따라 노출하거나 막을 수 있습니다.

protected routes 기본 예시

// guard 가 false 이면 해당 화면은 접근할 수 없습니다.
// 접근 중이던 화면이 보호 상태로 바뀌면 자동으로 다른 화면으로 이동합니다.
import { Stack } from 'expo-router'; const isLoggedIn = false; export default function RootLayout() { return ( <Stack> <Stack.Protected guard={!isLoggedIn}> <Stack.Screen name="login" /> </Stack.Protected> <Stack.Protected guard={isLoggedIn}> <Stack.Screen name="private" /> </Stack.Protected> <Stack.Screen name="index" /> </Stack> );
}

이 방식의 장점은 로그인 여부에 따라 화면을 단순히 보내버리는 수준이 아니라, 어떤 화면이 현재 활성 라우트 그룹에 들어올 수 있는지를 네비게이터 레벨에서 표현한다는 점입니다. 그리고 Redirect와 이름이 비슷해 헷갈릴 수 있지만, app config의 redirects는 오래된 경로나 외부 URL로 보내는 정적 매핑 용도이고, 페이지 안에서 바로 돌려보내는 Redirect 컴포넌트는 런타임 화면 분기 용도라는 차이가 있습니다.

실무에서 시작하기 좋은 폴더 구조

// 화면 파일은 src/app 아래에만 둡니다.
// 공용 컴포넌트와 훅은 src/app 밖으로 분리합니다.
src/ app/ _layout.tsx login.tsx (tabs)/ _layout.tsx index.tsx my.tsx post/ [id].tsx +not-found.tsx components/ Header.tsx hooks/ useAuth.ts

처음에는 이 정도 구조만으로도 충분합니다. 루트 Stack, 탭 그룹로그인 화면, 상세 화면, 없는 경로 처리, 공용 훅 분리 정도만 명확히 잡아도 프로젝트가 꽤 안정됩니다. 이후 규모가 커지면 feature 단위 분리, modal 파일, shared routes, platform-specific tabs 같은 주제로 확장하면 됩니다.

결론

Expo Router를 이해하는 가장 좋은 순서는 파일 이름이 경로가 된다는 감각을 먼저 잡고, 그다음 _layout.tsx가 관계를 정의하는 파일이라는 점을 익히는 것입니다. 그 위에 Link와 router.navigate, useLocalSearchParams, protected routes까지 얹으면 전체 흐름이 자연스럽게 연결됩니다.

정리하면 Expo Router는 단순히 화면 이동 API를 배우는 주제가 아니라, 폴더 구조와 네비게이션 설계를 함께 배우는 주제입니다. 그래서 실무에서도 중요한 것은 API를 많이 아는 것보다, src/app를 깔끔하게 유지하고 Stack과 Tabs, 인증 보호 범위를 읽기 쉬운 구조로 배치하는 일입니다.

라우팅 구조를 만든 뒤 화면 여백과 상단 UI를 다듬을 때는 Expo Safe Area 화면 여백 처리Expo Status Bar 화면별 설정 글을 함께 보면 좋습니다.

많이 받는 질문

Q. _layout.tsx는 꼭 있어야 하나요?
루트 src/app 바로 아래의 _layout.tsx는 사실상 기준점입니다. 이 파일은 다른 어떤 화면보다 먼저 렌더링되고, 초기화 코드와 전체 네비게이션 구조를 잡는 위치이기 때문에 Expo Router를 사용할 때 가장 먼저 이해해야 하는 파일입니다.

Q. (tabs) 같은 폴더 이름은 URL에 그대로 보이나요?
보이지 않습니다. 괄호 폴더는 route group이라서 구조를 나누기 위한 용도이며, URL 경로 조각으로 직접 노출되지 않습니다. 그래서 구조용 이름을 마음대로 정해도 주소가 그대로 바뀌는 것은 아닙니다.

Q. 인증은 Redirect만 알면 되나요?
간단한 분기에서는 Redirect를 바로 써도 되지만, 현재 문서 흐름에서는 protected routes를 함께 이해하는 편이 더 좋습니다. Redirect는 화면 단위 분기, protected routes는 네비게이터 단위 접근 제어라는 차이로 보면 정리가 쉽습니다.

이 글이 마음에 드세요?

RSS 피드를 구독하세요!

“Expo Router 사용법: app 폴더와 Stack Tabs 구조 잡기”에 대한 4개의 생각

댓글 남기기