expo-project-structure

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Expo Project Structure

Expo 项目结构

A starting skeleton for a new Expo app — one with no committed folder structure yet.
Apply only to new projects. If the app already has a layout, follow its existing conventions and leave files where they are — a default to start from, never a standard to enforce or migrate toward. When unsure whether a project is new, ask before moving anything.
The whole layout, assembled from the rules below:
├── assets/
├── scripts/
├── src/
│   ├── app/                       # Expo Router routes ONLY — every file is a route
│   │   ├── api/                   #   server API routes, grouped here
│   │   │   ├── user+api.ts
│   │   │   └── settings+api.ts
│   │   ├── _layout.tsx
│   │   ├── _layout.web.tsx         #   platform-specific layout
│   │   ├── index.tsx
│   │   └── settings.tsx
│   ├── components/                 # reusable UI: button, card, table…
│   │   ├── table/                  #   complex component → folder + index.tsx
│   │   │   ├── cell.tsx
│   │   │   └── index.tsx
│   │   ├── bar-chart.tsx
│   │   ├── bar-chart.web.tsx        #   platform-specific variant
│   │   └── button.tsx
│   ├── screens/                    # screen bodies that route files render
│   │   ├── home/
│   │   │   ├── card.tsx            #   used only by Home — not shared
│   │   │   └── index.tsx           #   rendered by src/app/index.tsx
│   │   └── settings.tsx
│   ├── server/                     # server-only helpers used by app/api
│   │   ├── auth.ts
│   │   └── db.ts
│   ├── utils/                      # standalone helpers + colocated tests
│   │   ├── format-date.ts
│   │   └── format-date.test.ts
│   ├── hooks/                      # reusable hooks: use-theme.ts…
│   ├── constants.ts
│   └── theme.ts
├── app.json
├── eas.json
└── package.json
这是一个全新Expo应用的初始骨架——适用于尚未确定文件夹结构的项目。
仅适用于新项目。如果应用已有既定布局,请遵循其现有约定,不要移动文件位置——这只是一个初始默认方案,绝非强制执行或迁移的标准。不确定项目是否为新项目时,移动文件前请先确认。
以下是整合所有规则后的完整布局:
├── assets/
├── scripts/
├── src/
│   ├── app/                       # Expo Router 路由专属目录——每个文件对应一个路由
│   │   ├── api/                   #   服务端API路由,集中存放于此
│   │   │   ├── user+api.ts
│   │   │   └── settings+api.ts
│   │   ├── _layout.tsx
│   │   ├── _layout.web.tsx         #   平台专属布局
│   │   ├── index.tsx
│   │   └── settings.tsx
│   ├── components/                 # 可复用UI组件:按钮、卡片、表格等
│   │   ├── table/                  #   复杂组件→文件夹+index.tsx
│   │   │   ├── cell.tsx
│   │   │   └── index.tsx
│   │   ├── bar-chart.tsx
│   │   ├── bar-chart.web.tsx        #   平台专属变体
│   │   └── button.tsx
│   ├── screens/                    # 路由文件渲染的页面主体
│   │   ├── home/
│   │   │   ├── card.tsx            #   仅Home页面使用——不共享
│   │   │   └── index.tsx           #   由src/app/index.tsx渲染
│   │   └── settings.tsx
│   ├── server/                     # app/api使用的服务端专属工具
│   │   ├── auth.ts
│   │   └── db.ts
│   ├── utils/                      # 独立工具函数+同目录测试文件
│   │   ├── format-date.ts
│   │   └── format-date.test.ts
│   ├── hooks/                      # 可复用钩子:use-theme.ts等
│   ├── constants.ts
│   └── theme.ts
├── app.json
├── eas.json
└── package.json

src/
and
src/app

src/
src/app

Keep app code under
src/
to separate it from config files. Expo Router supports both
app/
and
src/app/
out of the box — to switch, move the folder and restart the bundler. The default template aliases
@/*
to
./src/*
in
tsconfig.json
.
src/app
is routes-only: every file there becomes a route, so nothing else belongs in it. Everything below lives in sibling folders.
将应用代码放在
src/
目录下,与配置文件区分开。Expo Router原生支持
app/
src/app/
两种目录结构——如需切换,只需移动文件夹并重启打包工具。默认模板在
tsconfig.json
中设置了
@/*
别名指向
./src/*
src/app
专属路由目录:该目录下的每个文件都会成为一个路由,因此其他内容都不应放在这里。所有其他代码都应放在同级目录中。

components/ — reusable UI

components/ —— 可复用UI组件

Generic, reused UI (button, card, table) with one named export each. Name files in kebab-case (
bar-chart.tsx
), matching the default
create-expo-app
template. When a component grows, give it its own folder with the root in
index.tsx
and colocate its private sub-components beside it — the import path (
@/components/table
) stays unchanged.
通用的可复用UI组件(如按钮、卡片、表格),每个文件对应一个命名导出。文件名采用短横线命名法(kebab-case)(如
bar-chart.tsx
),与默认的
create-expo-app
模板保持一致。当组件变得复杂时,可为其创建独立文件夹,将根组件放在
index.tsx
中,并将私有子组件与其放在同一目录下——这样导入路径(
@/components/table
)保持不变。

screens/ — screen bodies

screens/ —— 页面主体

Because
app/
files must be routes, complex screen UI that isn't reused has no home there. Once a screen grows big enough to need breaking out to separate components, put it in
screens/
and let each route just render its screen:
tsx
import { Home } from "@/screens/home";

export default function HomeScreen() {
  // route-specific concerns only — e.g. read url params here
  return <Home />;
}
Colocate a screen's private components inside its folder (
screens/home/components/
). A bonus: the same screen can render under multiple routes.
由于
app/
目录下的文件必须是路由,无法复用的复杂页面UI没有合适的存放位置。当页面复杂到需要拆分为多个组件时,将其放在
screens/
目录下,让每个路由仅负责渲染对应的页面:
tsx
import { Home } from "@/screens/home";

export default function HomeScreen() {
  // 仅处理路由相关逻辑——例如在此读取URL参数
  return <Home />;
}
将页面的私有组件放在其专属文件夹内(如
screens/home/components/
)。额外优势:同一个页面可以在多个路由下渲染。

server/ + app/api/ — separate server code

server/ + app/api/ —— 分离服务端代码

Appending
+api
to a file in
app/
makes it a server API route. Server code is different from frontend code — it runs in a Node-like server environment (deployed with EAS Hosting or on third-party services) and can read secret env vars (
process.env.X
, not just
EXPO_PUBLIC_*
). Keep it apart:
  • Group all routes under
    app/api/
    /api/user
    ,
    /api/settings
    . This colocates them and avoids collisions (e.g. a
    /user
    screen and a
    /user
    route).
  • Put shared server-only helpers in
    src/server/
    .
  • Consider ESLint rules that fence
    +api
    files and
    server/
    off from frontend-only checks.
app/
目录下的文件名后添加
+api
,即可将其设为服务端API路由。服务端代码与前端代码不同——它运行在类Node的服务端环境中(通过EAS Hosting或第三方服务部署),并且可以读取私密环境变量(
process.env.X
,而非仅
EXPO_PUBLIC_*
)。请将两者分离:
  • 将所有API路由集中放在
    app/api/
    目录下→对应
    /api/user
    /api/settings
    。这样可以集中管理路由,避免冲突(例如
    /user
    页面和
    /user
    路由)。
  • 将共享的服务端专属工具放在
    src/server/
    目录下。
  • 可考虑使用ESLint规则,将
    +api
    文件和
    server/
    目录与前端专属检查隔离开。

Platform-specific code

平台专属代码

Small differences: use
Platform.select
/
Platform.OS
. For larger ones, split into platform files instead of inline
if/else
bar-chart.tsx
+
bar-chart.web.tsx
, imported extension-free (
@/components/bar-chart
); Metro picks the right file per target.
  • Props must be identical across variants.
  • A default file (no platform extension) is always required — make it a no-op if the component is single-platform.
  • Supported extensions:
    .ios
    ,
    .android
    ,
    .native
    ,
    .web
    .
小差异:使用
Platform.select
/
Platform.OS
处理。对于较大差异,将代码拆分为平台专属文件,而非使用内联
if/else
——例如
bar-chart.tsx
+
bar-chart.web.tsx
,导入时无需指定扩展名(
@/components/bar-chart
);Metro会根据目标平台自动选择正确的文件。
  • 不同平台变体的props必须完全一致。
  • 必须存在一个默认文件(无平台扩展名)——如果组件仅支持单一平台,可将默认文件设为空实现。
  • 支持的扩展名:
    .ios
    .android
    .native
    .web

Colocate styles and tests

样式与测试文件同目录存放

  • Styles: keep the
    StyleSheet.create({ ... })
    object at the bottom of the component file rather than in a separate
    .styles
    file.
  • Tests: put
    format-date.test.ts
    next to
    format-date.ts
    (preferred over a separate
    __tests__/
    folder) so tested files are obvious at a glance.
  • 样式:将
    StyleSheet.create({ ... })
    对象放在组件文件底部,而非单独的
    .styles
    文件中。
  • 测试:将
    format-date.test.ts
    放在
    format-date.ts
    旁边(优先于单独的
    __tests__/
    文件夹),这样一眼就能看到哪些文件有对应的测试。

AI and config files

AI与配置文件

Agent instructions live at the repo root —
AGENTS.md
/
CLAUDE.md
, with project skills under
.claude/
. Other config and assets stay outside
src/
:
app.json
/
app.config.ts
,
eas.json
,
package.json
,
assets/
, and
scripts/
.

Based on Expo app folder structure best practices by Kadi Kraman. For
src/
precedence and alias mechanics, see the Expo docs.
Agent指令存放在仓库根目录——
AGENTS.md
/
CLAUDE.md
,项目技能存放在
.claude/
目录下。其他配置和资源文件放在
src/
外部:
app.json
/
app.config.ts
eas.json
package.json
assets/
scripts/

基于Kadi Kraman撰写的Expo应用文件夹结构最佳实践。关于
src/
目录的优先级和别名机制,请查看Expo文档