expo-project-structure
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseExpo 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.jsonsrc/
and src/app
src/src/appsrc/
和 src/app
src/src/appKeep app code under to separate it from config files. Expo Router supports both and out of the box — to switch, move the folder and restart the bundler. The default template aliases to in .
src/app/src/app/@/*./src/*tsconfig.jsonsrc/app将应用代码放在目录下,与配置文件区分开。Expo Router原生支持和两种目录结构——如需切换,只需移动文件夹并重启打包工具。默认模板在中设置了别名指向。
src/app/src/app/tsconfig.json@/*./src/*src/appcomponents/ — reusable UI
components/ —— 可复用UI组件
Generic, reused UI (button, card, table) with one named export each. Name files in kebab-case (), matching the default template. When a component grows, give it its own folder with the root in and colocate its private sub-components beside it — the import path () stays unchanged.
bar-chart.tsxcreate-expo-appindex.tsx@/components/table通用的可复用UI组件(如按钮、卡片、表格),每个文件对应一个命名导出。文件名采用短横线命名法(kebab-case)(如),与默认的模板保持一致。当组件变得复杂时,可为其创建独立文件夹,将根组件放在中,并将私有子组件与其放在同一目录下——这样导入路径()保持不变。
bar-chart.tsxcreate-expo-appindex.tsx@/components/tablescreens/ — screen bodies
screens/ —— 页面主体
Because 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 and let each route just render its screen:
app/screens/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 (). A bonus: the same screen can render under multiple routes.
screens/home/components/由于目录下的文件必须是路由,无法复用的复杂页面UI没有合适的存放位置。当页面复杂到需要拆分为多个组件时,将其放在目录下,让每个路由仅负责渲染对应的页面:
app/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 to a file in 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 (, not just ). Keep it apart:
+apiapp/process.env.XEXPO_PUBLIC_*- Group all routes under →
app/api/,/api/user. This colocates them and avoids collisions (e.g. a/api/settingsscreen and a/userroute)./user - Put shared server-only helpers in .
src/server/ - Consider ESLint rules that fence files and
+apioff from frontend-only checks.server/
在目录下的文件名后添加,即可将其设为服务端API路由。服务端代码与前端代码不同——它运行在类Node的服务端环境中(通过EAS Hosting或第三方服务部署),并且可以读取私密环境变量(,而非仅)。请将两者分离:
app/+apiprocess.env.XEXPO_PUBLIC_*- 将所有API路由集中放在目录下→对应
app/api/、/api/user。这样可以集中管理路由,避免冲突(例如/api/settings页面和/user路由)。/user - 将共享的服务端专属工具放在目录下。
src/server/ - 可考虑使用ESLint规则,将文件和
+api目录与前端专属检查隔离开。server/
Platform-specific code
平台专属代码
Small differences: use / . For larger ones, split into platform files instead of inline — + , imported extension-free (); Metro picks the right file per target.
Platform.selectPlatform.OSif/elsebar-chart.tsxbar-chart.web.tsx@/components/bar-chart- 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
小差异:使用 / 处理。对于较大差异,将代码拆分为平台专属文件,而非使用内联——例如 + ,导入时无需指定扩展名();Metro会根据目标平台自动选择正确的文件。
Platform.selectPlatform.OSif/elsebar-chart.tsxbar-chart.web.tsx@/components/bar-chart- 不同平台变体的props必须完全一致。
- 必须存在一个默认文件(无平台扩展名)——如果组件仅支持单一平台,可将默认文件设为空实现。
- 支持的扩展名:、
.ios、.android、.native。.web
Colocate styles and tests
样式与测试文件同目录存放
- Styles: keep the object at the bottom of the component file rather than in a separate
StyleSheet.create({ ... })file..styles - Tests: put next to
format-date.test.ts(preferred over a separateformat-date.tsfolder) so tested files are obvious at a glance.__tests__/
- 样式:将对象放在组件文件底部,而非单独的
StyleSheet.create({ ... })文件中。.styles - 测试:将放在
format-date.test.ts旁边(优先于单独的format-date.ts文件夹),这样一眼就能看到哪些文件有对应的测试。__tests__/
AI and config files
AI与配置文件
Agent instructions live at the repo root — / , with project skills under . Other config and assets stay outside : / , , , , and .
AGENTS.mdCLAUDE.md.claude/src/app.jsonapp.config.tseas.jsonpackage.jsonassets/scripts/Based on Expo app folder structure best practices by Kadi Kraman. For precedence and alias mechanics, see the Expo docs.
src/Agent指令存放在仓库根目录—— / ,项目技能存放在目录下。其他配置和资源文件放在外部: / 、、、和。
AGENTS.mdCLAUDE.md.claude/src/app.jsonapp.config.tseas.jsonpackage.jsonassets/scripts/