From 045dcfd3dec24ce25d1e2da5da93039d893cee8d Mon Sep 17 00:00:00 2001 From: Adam Zvada Date: Thu, 25 Jun 2026 00:59:39 +0200 Subject: [PATCH 1/4] Add expo-project-structure skill for greenfield app layout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New model-invoked skill documenting Expo's recommended folder structure (the SDK 55+ src/ layout, src/app routes-only, feature colocation) for brand-new projects. Framed as greenfield guidance only — it never restructures an existing app. Added to the plugin README skill list. Co-Authored-By: Claude Opus 4.8 (1M context) --- plugins/expo/README.md | 2 + .../skills/expo-project-structure/SKILL.md | 58 +++++++++++++++++++ 2 files changed, 60 insertions(+) create mode 100644 plugins/expo/skills/expo-project-structure/SKILL.md diff --git a/plugins/expo/README.md b/plugins/expo/README.md index 8e071b4..95a6a7f 100644 --- a/plugins/expo/README.md +++ b/plugins/expo/README.md @@ -6,6 +6,7 @@ Official AI agent skills from the Expo team for building, deploying, upgrading, ### App Design +- Recommends a starting folder structure for new (greenfield) projects - Provides UI guidelines following Apple Human Interface Guidelines - Covers Expo Router navigation patterns (stacks, tabs, modals, sheets) - Explains native iOS controls, SF Symbols, animations, and visual effects @@ -69,6 +70,7 @@ Official AI agent skills from the Expo team for building, deploying, upgrading, - **expo-api-routes** — Create API routes in Expo Router with EAS Hosting - **expo-brownfield** — Integrate Expo and React Native into existing native iOS or Android apps - **expo-dev-client** — Build and distribute Expo development clients locally or via TestFlight +- **expo-project-structure** — Recommended folder structure for new (greenfield) Expo projects - **expo-tailwind-setup** — Set up Tailwind CSS v4 in Expo with NativeWind v5 - **expo-ui** — Native UI with @expo/ui: universal cross-platform components first, with SwiftUI and Jetpack Compose for platform-specific needs - **native-data-fetching** — Network requests, API calls, caching, and offline support diff --git a/plugins/expo/skills/expo-project-structure/SKILL.md b/plugins/expo/skills/expo-project-structure/SKILL.md new file mode 100644 index 0000000..08a6fc9 --- /dev/null +++ b/plugins/expo/skills/expo-project-structure/SKILL.md @@ -0,0 +1,58 @@ +--- +name: expo-project-structure +description: Folder structure for a new Expo app — the SDK 55+ `src/` layout, Expo Router `app/` for routes, plus `components/`, `features/`, `hooks/`, `lib/`, `constants/`. Use when scaffolding or laying out a greenfield Expo project, or deciding where a file should live in one. Greenfield guidance only — never restructure an existing app to match. +version: 1.0.0 +license: MIT +--- + +# Expo Project Structure + +A starting skeleton for a **greenfield** Expo app — one with no committed folder structure yet. + +**Apply only to greenfield projects.** If the app already has a layout, follow its existing conventions and leave files where they are — this is a default to start from, never a standard to enforce or migrate toward. When unsure whether a project counts as greenfield, ask before moving anything. + +## The `src/` layout + +Since SDK 55, the default `create-expo-app` template ships a top-level `src/` — don't recreate it. For a blank or pre-55 project, create `src/` yourself and point the import alias at it in `tsconfig.json`: `"@/*": ["./src/*"]`. + +``` +src/ + app/ # Expo Router routes ONLY — screens, layouts, navigation + components/ # UI shared across features + ui/ # design-system primitives (Button, Card, Text) + common/ # other generic shared components + features/ # Self-contained feature modules — auth/, feed/, profile/ + hooks/ # Global custom hooks + lib/ # API clients, SDK wrappers, third-party config + constants/ # Theme, colors, layout metrics, config values + utils/ # Pure helper functions + store/ # Global state (Redux / Zustand / Jotai), if any + types/ # Shared TypeScript types +``` + +Create a directory on first need — an empty `store/` or `types/` earns its place only when something fills it. + +## `src/app` is routes-only + +`src/app` holds nothing but route files — screens, `_layout` files, and navigation. Everything else (components, hooks, helpers) lives in the sibling directories above. If both `app/` and `src/app/` exist, Expo Router uses `src/app/` only. + +## Colocate by feature; promote only what's shared + +The lever that keeps a growing app maintainable: **colocate** each feature's own code inside its `features//` folder, and lift code up to the shared directories only once a *second* feature actually uses it. + +``` +features/auth/ + components/ # used only by auth — not in src/components + hooks/ + api.ts + types.ts +``` + +- A component used by one screen stays with that screen or feature. Only genuinely cross-feature components belong in `src/components/`. +- Same rule for `hooks/`, `utils/`, and `types/`: feature-local until a second feature needs them. + +## Stays at the project root + +Config and assets stay outside `src/`: `app.json` / `app.config.ts`, `package.json`, `metro.config.js`, `tsconfig.json`, `assets/`, and `public/`. + +For the `src/` precedence and alias mechanics, see Expo's docs: https://docs.expo.dev/router/reference/src-directory/ From d12cb330cae7fb9c7e8b4c5a572107b1e5b345a3 Mon Sep 17 00:00:00 2001 From: Adam Zvada Date: Wed, 1 Jul 2026 00:06:23 +0200 Subject: [PATCH 2/4] Rewrite expo-project-structure to match Kadi's blog (PR review) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Address @kadikraman's review on PR #91: - Drop "greenfield" (collides with Expo's brownfield term) — use "new" - Remove SDK 55 note from the description - Replace the invented web-style folders (lib/, store/, types/, components/ui|common, feature-based colocation) with the blog's actual model: screens/, server/ + app/api/, platform-specific files, colocated styles and tests, kebab-case filenames - Add a note on where AI instruction files live (AGENTS.md/CLAUDE.md) - Attribute the source blog post Co-Authored-By: Claude Opus 4.8 (1M context) --- .../skills/expo-project-structure/SKILL.md | 116 +++++++++++++----- 1 file changed, 82 insertions(+), 34 deletions(-) diff --git a/plugins/expo/skills/expo-project-structure/SKILL.md b/plugins/expo/skills/expo-project-structure/SKILL.md index 08a6fc9..a5d4172 100644 --- a/plugins/expo/skills/expo-project-structure/SKILL.md +++ b/plugins/expo/skills/expo-project-structure/SKILL.md @@ -1,58 +1,106 @@ --- name: expo-project-structure -description: Folder structure for a new Expo app — the SDK 55+ `src/` layout, Expo Router `app/` for routes, plus `components/`, `features/`, `hooks/`, `lib/`, `constants/`. Use when scaffolding or laying out a greenfield Expo project, or deciding where a file should live in one. Greenfield guidance only — never restructure an existing app to match. +description: Folder structure for a new Expo app. Use when scaffolding or laying out a new Expo project with Expo Router, or deciding where a file should live in one. For new projects only — never restructure an existing app to match. version: 1.0.0 license: MIT --- # Expo Project Structure -A starting skeleton for a **greenfield** Expo app — one with no committed folder structure yet. +A starting skeleton for a **new** Expo app — one with no committed folder structure yet. -**Apply only to greenfield projects.** If the app already has a layout, follow its existing conventions and leave files where they are — this is a default to start from, never a standard to enforce or migrate toward. When unsure whether a project counts as greenfield, ask before moving anything. +**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 `src/` layout - -Since SDK 55, the default `create-expo-app` template ships a top-level `src/` — don't recreate it. For a blank or pre-55 project, create `src/` yourself and point the import alias at it in `tsconfig.json`: `"@/*": ["./src/*"]`. +The whole layout, assembled from the rules below: ``` -src/ - app/ # Expo Router routes ONLY — screens, layouts, navigation - components/ # UI shared across features - ui/ # design-system primitives (Button, Card, Text) - common/ # other generic shared components - features/ # Self-contained feature modules — auth/, feed/, profile/ - hooks/ # Global custom hooks - lib/ # API clients, SDK wrappers, third-party config - constants/ # Theme, colors, layout metrics, config values - utils/ # Pure helper functions - store/ # Global state (Redux / Zustand / Jotai), if any - types/ # Shared TypeScript types +├── 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 ``` -Create a directory on first need — an empty `store/` or `types/` earns its place only when something fills it. +## `src/` and `src/app` -## `src/app` is routes-only +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` holds nothing but route files — screens, `_layout` files, and navigation. Everything else (components, hooks, helpers) lives in the sibling directories above. If both `app/` and `src/app/` exist, Expo Router uses `src/app/` only. +`src/app` is **routes-only**: every file there becomes a route, so nothing else belongs in it. Everything below lives in sibling folders. -## Colocate by feature; promote only what's shared +## components/ — reusable UI -The lever that keeps a growing app maintainable: **colocate** each feature's own code inside its `features//` folder, and lift code up to the shared directories only once a *second* feature actually uses it. +Generic, reused UI (button, card, table) with one named export each. Name files in **kebab-case** (`bar-chart.tsx`), matching the SDK 55 default 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. +## screens/ — screen bodies + +Because `app/` files must be routes, complex screen UI that isn't reused has no home there. 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 ; +} ``` -features/auth/ - components/ # used only by auth — not in src/components - hooks/ - api.ts - types.ts -``` -- A component used by one screen stays with that screen or feature. Only genuinely cross-feature components belong in `src/components/`. -- Same rule for `hooks/`, `utils/`, and `types/`: feature-local until a second feature needs them. +**Colocate** a screen's private components inside its folder (`screens/home/components/`). A bonus: the same screen can render under multiple routes. + +## server/ + app/api/ — separate server code + +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 EAS Hosting environment 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. -## Stays at the project root +## Platform-specific code -Config and assets stay outside `src/`: `app.json` / `app.config.ts`, `package.json`, `metro.config.js`, `tsconfig.json`, `assets/`, and `public/`. +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`. + +## 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. + +## AI and config files + +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/`. + +--- -For the `src/` precedence and alias mechanics, see Expo's docs: https://docs.expo.dev/router/reference/src-directory/ +Based on [Expo app folder structure best practices](https://expo.dev/blog/expo-app-folder-structure-best-practices) by Kadi Kraman. For `src/` precedence and alias mechanics, see the [Expo docs](https://docs.expo.dev/router/reference/src-directory/). From c2c2d967997bbc9bc4a53f03ff509d05246d57ac Mon Sep 17 00:00:00 2001 From: Adam Zvada Date: Wed, 1 Jul 2026 15:53:38 +0200 Subject: [PATCH 3/4] Drop last SDK 55 reference from expo-project-structure Kebab-case rule now cites the default create-expo-app template rather than a version number, honoring the review's "don't version-gate" note. Co-Authored-By: Claude Opus 4.8 (1M context) --- plugins/expo/skills/expo-project-structure/SKILL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/expo/skills/expo-project-structure/SKILL.md b/plugins/expo/skills/expo-project-structure/SKILL.md index a5d4172..485d357 100644 --- a/plugins/expo/skills/expo-project-structure/SKILL.md +++ b/plugins/expo/skills/expo-project-structure/SKILL.md @@ -59,7 +59,7 @@ Keep app code under `src/` to separate it from config files. Expo Router support ## components/ — reusable UI -Generic, reused UI (button, card, table) with one named export each. Name files in **kebab-case** (`bar-chart.tsx`), matching the SDK 55 default 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. +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. ## screens/ — screen bodies From 540294476231f3292f6eb51ce38372319a2d8197 Mon Sep 17 00:00:00 2001 From: Adam Zvada Date: Thu, 2 Jul 2026 15:19:16 +0200 Subject: [PATCH 4/4] Bump expo plugin to 1.6.0 for the expo-project-structure skill MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The plugin-version-bump CI requires the Claude, Codex, and Cursor manifests to be bumped above main (1.5.0) whenever a versioned plugin file changes — adding the new skill's SKILL.md triggered it. Also drops "greenfield" from the README entries to match the skill's wording. Co-Authored-By: Claude Opus 4.8 (1M context) --- plugins/expo/.claude-plugin/plugin.json | 2 +- plugins/expo/.codex-plugin/plugin.json | 2 +- plugins/expo/.cursor-plugin/plugin.json | 2 +- plugins/expo/README.md | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/plugins/expo/.claude-plugin/plugin.json b/plugins/expo/.claude-plugin/plugin.json index 82849f7..535e84b 100644 --- a/plugins/expo/.claude-plugin/plugin.json +++ b/plugins/expo/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "expo", - "version": "1.5.0", + "version": "1.6.0", "description": "Official Expo skills for building, deploying, upgrading, and debugging Expo apps", "author": { "name": "Expo Team", diff --git a/plugins/expo/.codex-plugin/plugin.json b/plugins/expo/.codex-plugin/plugin.json index 8c63ac0..afedcb4 100644 --- a/plugins/expo/.codex-plugin/plugin.json +++ b/plugins/expo/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "expo", - "version": "1.5.0", + "version": "1.6.0", "description": "Official Expo skills for building, deploying, upgrading, and debugging Expo and React Native apps.", "author": { "name": "Expo Team", diff --git a/plugins/expo/.cursor-plugin/plugin.json b/plugins/expo/.cursor-plugin/plugin.json index 2e15e93..0175432 100644 --- a/plugins/expo/.cursor-plugin/plugin.json +++ b/plugins/expo/.cursor-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "expo", "displayName": "Expo", - "version": "1.5.0", + "version": "1.6.0", "description": "Official Expo skills for building, deploying, upgrading, and debugging Expo and React Native apps.", "author": { "name": "Expo Team", diff --git a/plugins/expo/README.md b/plugins/expo/README.md index 2b7af04..7e12478 100644 --- a/plugins/expo/README.md +++ b/plugins/expo/README.md @@ -6,7 +6,7 @@ Official AI agent skills from the Expo team for building, deploying, upgrading, ### App Design -- Recommends a starting folder structure for new (greenfield) projects +- Recommends a starting folder structure for new projects - Provides UI guidelines following Apple Human Interface Guidelines - Covers Expo Router navigation patterns (stacks, tabs, modals, sheets) - Explains native iOS controls, SF Symbols, animations, and visual effects @@ -70,7 +70,7 @@ Official AI agent skills from the Expo team for building, deploying, upgrading, - **expo-api-routes** — Create API routes in Expo Router with EAS Hosting - **expo-brownfield** — Integrate Expo and React Native into existing native iOS or Android apps - **expo-dev-client** — Build and distribute Expo development clients locally or via TestFlight -- **expo-project-structure** — Recommended folder structure for new (greenfield) Expo projects +- **expo-project-structure** — Recommended folder structure for new Expo projects - **expo-tailwind-setup** — Set up Tailwind CSS v4 in Expo with NativeWind v5 - **expo-ui** — Native UI with @expo/ui: universal cross-platform components first, with SwiftUI and Jetpack Compose for platform-specific needs - **native-data-fetching** — Network requests, API calls, caching, and offline support