Released · improving
React Native guide · 2/6
This chapter looks at the files that make up an Expo project and a Community CLI project: where the app starts, and where settings such as the app name, icon and permissions live.
A project created with npx create-expo-app@latest looks roughly like this. The exact files vary with the Expo SDK version and template, and some templates use src/app/ instead of app/.
my-app/
app/ screens (routes)
_layout.tsx root layout
(tabs)/
_layout.tsx tab navigator
index.tsx first tab (/)
explore.tsx second tab (/explore)
assets/ images and fonts
components/ reusable components
constants/ constants such as colors
hooks/ custom hooks
app.json app configuration
package.json
tsconfig.jsonThe main field in package.json points to expo-router/entry, so on launch Expo Router reads the app/ directory and builds the screens from it. To remove the example screens and start from an empty app/ directory, run the template's npm run reset-project script.
Expo Router is a file-based router: the path of a file inside app/ becomes the route.
| File | Route or role |
|---|---|
app/index.tsx | /, the initial screen |
app/settings.tsx | /settings |
app/posts/[id].tsx | dynamic route such as /posts/42 |
app/(tabs)/... | group: parentheses keep it out of the URL |
app/_layout.tsx | layout wrapping sibling screens (Stack, Tabs and so on) |
app/+not-found.tsx | shown when no route matches |
A layout file decides which navigator presents the screens in its folder. Here is a root layout using a stack navigator:
import { Stack } from "expo-router";
export default function RootLayout() {
return (
<Stack>
<Stack.Screen name="index" options={{ title: "Home" }} />
<Stack.Screen name="settings" options={{ title: "Settings" }} />
</Stack>
);
}If you choose the blank template without a router (--template blank-typescript), App.tsx is the root component and index.ts registers it with registerRootComponent(App).
The app name, icon, splash screen, bundle identifiers, permissions and config plugins go under the expo key in app.json.
{
"expo": {
"name": "My App",
"slug": "my-app",
"version": "1.0.0",
"orientation": "portrait",
"icon": "./assets/images/icon.png",
"scheme": "myapp",
"ios": { "bundleIdentifier": "com.example.myapp" },
"android": { "package": "com.example.myapp" },
"plugins": ["expo-router"]
}
}When values depend on environment variables, use app.config.ts (or app.config.js). It receives the contents of app.json as config and can return a modified version.
import type { ExpoConfig, ConfigContext } from "expo/config";
export default ({ config }: ConfigContext): ExpoConfig => ({
...config,
name: process.env.APP_VARIANT === "development" ? "My App (Dev)" : "My App",
slug: "my-app",
});An Expo project starts without android/ and ios/. Expo follows Continuous Native Generation (CNG): it generates the native projects on demand from app.json and config plugins. npx expo run:android and EAS Build run this step for you, and you can also run it directly:
npx expo prebuild
npx expo prebuild --cleanTreating the native folders as build output and listing them in .gitignore keeps all configuration in one place, app.json. If instead you edit the generated folders and commit them, you take over their maintenance, and native settings you later change in app.json are no longer applied automatically.
A project created with the CLI includes the native folders from the start.
| File or folder | Role |
|---|---|
index.js | entry point that registers the root component with AppRegistry |
App.tsx | root component |
android/ | Gradle-based Android project |
ios/ | Xcode project and Podfile |
metro.config.js, babel.config.js | bundler and transform settings |
app.json | app name registered with the native side |
import { AppRegistry } from "react-native";
import App from "./App";
import { name as appName } from "./app.json";
AppRegistry.registerComponent(appName, () => App);app/ defines the screens, and _layout.tsx files choose the navigators.app.json; dynamic ones go in app.config.ts.android/ and ios/ are generated by npx expo prebuild; whether to commit them is a team decision.AppRegistry in index.js is the entry point and you maintain the native folders yourself.
0 comments
Sign in · Sign in to leave a comment.
Be the first to comment.