0% completed
Understanding Project Structure
On This Page
How the Application Starts
Configuring the Application with app.json
The Folders
The Other Files
Why There Are No android and ios Folders
Babel and Metro Configuration
Organizing Your Own Code in src/
App.js is not where your application starts, even though it is the file you edit first. The terminal line from your first run named a different file:
Android Bundled 4613ms index.js (744 modules)
To see why Metro started at index.js, open the MyFirstApp folder in a code editor such as VS Code. After one run of npx expo start, a project created from the blank template contains these items:
MyFirstApp/ ├── .claude/ ├── .expo/ ├── .git/ ├── assets/ ├── node_modules/ ├── .gitignore ├── AGENTS.md ├── App.js ├── LICENSE ├── app.json ├── index.js ├── package-lock.json └── package.json
Three of these files decide how the application starts, so this lesson begins with them.
How the Application Starts
The chain begins in package.json, which describes the project. Its main field names the file where the code starts, and its dependencies field lists the libraries the project uses, with version ranges. Its scripts field defines short commands, so npm start runs expo start:
{ "name": "myfirstapp", "version": "1.0.0", "main": "index.js", "dependencies": { "expo": "~58.0.22", "expo-status-bar": "~58.0.4", "react": "19.3.0", "react-native": "0.88.1" }, "scripts": { "start": "expo start", "android": "expo start --android", "ios": "expo start --ios", "web": "expo start --web" }, "private": true }
Your version numbers may be newer than these. The main field leads Metro to index.js, which is the entry point: the file where your code starts loading. It is short, and you will rarely edit it:
import { registerRootComponent } from 'expo'; import App from './App'; // registerRootComponent calls AppRegistry.registerComponent('main', () => App); // It also ensures that whether you load the app in Expo Go or in a native build, // the environment is set up appropriately registerRootComponent(App);
index.js imports your App component and registers it with React Native as the root component. The root component is the one at the top of the tree, so everything your application displays is rendered inside it. That is why App.js is where you start working, even though the application starts from index.js.
Metro then follows the imports outward from index.js, and any file that is reachable from there becomes part of the bundle. A new file does nothing until a file in that chain imports it.
Configuring the Application with app.json
Some settings belong to the application as a whole rather than to any screen, and app.json holds them. Here is the file with its platform sections left out:
{ "expo": { "name": "MyFirstApp", "slug": "MyFirstApp", "version": "1.0.0", "orientation": "portrait", "icon": "./assets/icon.png", "userInterfaceStyle": "light" } }
The name field is the title shown on the phone, icon points to the application's image, and orientation locks the screen to portrait. The full file also has ios, android, and web sections with platform settings. Expo uses this file to decide how the project loads in Expo Go and how to generate the native projects.
The Folders
assets/ holds images, fonts, and other static files that your application uses. The template places six images here: icon.png, splash-icon.png, favicon.png, and three Android icon layers.
node_modules/ contains the installed code of every library in package.json and of the libraries they depend on. It is generated by npm install, so never edit it by hand. If you delete it, running npm install restores it.
.expo/ holds local data that Expo creates while you work with the development server, so it may not appear immediately, and you can ignore it. .git/ is a Git repository, which create-expo-app created for you with a first commit.
The Other Files
package-lock.json records the exact version of every installed package, so that another computer installs the same versions. npm maintains this file, and you commit it to version control.
.gitignore lists what Git should leave out of version control. It includes node_modules/ and .expo/, because both can be recreated. It also lists two entries that explain something you may have noticed: /ios and /android.
AGENTS.md and .claude/ contain instructions for AI coding assistants. Your application does not use them, and you can delete them. LICENSE holds the license text of the template.
Why There Are No android and ios Folders
An Expo project does not keep native folders by default. When they are needed, for example to build the application, Expo generates them from your app.json and installed libraries. You can trigger this yourself with npx expo prebuild. Because they can be regenerated, they stay out of version control, and any manual change inside them can be lost when they are next regenerated. While you develop in Expo Go, you do not need them at all, since Expo Go is already a compiled native application.
A project created with the React Native Community CLI is different, because you own its native code:
| File or folder | Blank Expo project | React Native Community CLI project |
|---|---|---|
android/, ios/ | Not present, generated when needed | Present and maintained by you |
| First screen | App.js | App.tsx |
index.js | Calls registerRootComponent | Present |
app.json | Application settings | Present |
babel.config.js, metro.config.js | Not present, defaults are used | Present |
tsconfig.json, jest.config.js, Gemfile | Not present | Present |
Babel and Metro Configuration
Two tools process your code before it reaches the phone. Babel is a compiler that rewrites your source code into JavaScript the engine can run, and the next chapter shows what it does to your tags. Metro, as you saw earlier, bundles the result.
The blank project has no configuration file for either tool, and it still builds, because Expo supplies defaults. You only create these files when you need to change that behavior:
npx expo customize babel.config.js npx expo customize metro.config.js
Organizing Your Own Code in src/
The template gives you one screen in one file, which is enough for the first few chapters. As an application grows, many teams add a src/ folder and divide their code into subfolders. This is a convention, so nothing creates or requires it, and the names below are common choices:
src/components/: reusable pieces such as buttons, headers, and cards.src/screens/: one file per screen, such as a home screen or a login screen.src/navigation/: the configuration for moving between screens.src/styles/: shared styles, if you keep them in separate files.src/utils/: helper functions used across the application.
Because index.js imports ./App, you must update that import if you move App.js into src/.
Reading Progress
0%
On This Page
How the Application Starts
Configuring the Application with app.json
The Folders
The Other Files
Why There Are No android and ios Folders
Babel and Metro Configuration
Organizing Your Own Code in src/