8 Folder Structure Best Practices for Expo Apps in 2026

Discover 8 folder structure best practices for React Native & Expo apps. Learn feature-based, monorepo, and scalable models to build maintainable codebases.

Profile photo of ParthParth
11th Jul 2026
Featured image for 8 Folder Structure Best Practices for Expo Apps in 2026

Every Expo app feels clean in week one. You've got app, maybe src, a few components, some hooks, and just enough confidence to believe the structure will hold. Then the second auth flow lands, web support gets added, AI tooling starts generating files in odd places, and the neat little tree becomes a scavenger hunt.

That's when folder structure stops being cosmetic and starts affecting delivery speed. Developers lose time browsing, imports get messy, shared code leaks into feature code, and simple changes touch too many files. Good folder structure best practices prevent that. They don't make the app magically scalable, but they remove a lot of friction that kills momentum.

A practical rule from data organization guidance is to keep hierarchies shallow. Axiom Data Science recommends limiting folder depth to no more than three levels, with three to four levels as the sweet spot for professional work, and keeping top-level labels to no more than 10 so navigation stays manageable (Axiom Data Science folder organization guidance). That advice maps surprisingly well to Expo codebases.

If you care about maintainability, these key software architecture principles matter just as much as the React Native code itself.

Table of Contents

1. Feature-Based (Domain-Driven) Folder Structure

Feature-based structure is the default I trust most for real products. Instead of separating code into components, hooks, and services at the top level, you group by business domain like auth, billing, profile, notifications, or marketplace. Each folder contains the UI, hooks, API calls, tests, and types that belong to that feature.

This matches how product work arrives. Teams rarely say, “today we are editing the hooks layer.” They say, “we're changing onboarding,” or “we're adding saved items.” If the folder structure mirrors that language, developers find the right files faster and make fewer accidental cross-feature edits.

A wooden desk featuring three organized stacks of green, yellow, and blue file folders for office organization.A wooden desk featuring three organized stacks of green, yellow, and blue file folders for office organization.

Why feature folders age better

A feature folder makes ownership obvious. An auth folder can hold components, hooks, api, state, and index.ts, while shared stays reserved for code that is reused across multiple domains. That last part matters. Many teams say “shared” when they mean “I don't know where this goes.”

A practical shape for Expo looks like this:

  • src/features/auth for sign-in screens, auth hooks, tokens, and guards
  • src/features/profile for profile forms, avatar upload logic, and related queries
  • src/features/marketplace for listing cards, filters, and purchase flow pieces

Practical rule: If deleting a folder would remove a user-facing capability, it's probably a real feature. If not, it's probably a shared utility or infrastructure concern.

Keep feature trees shallow. Significantly nested domain trees look tidy on day one and turn into a maze later. In practice, feature > subdomain > file is usually enough, with an occasional extra layer for complex flows. That fits the broader guidance to avoid over-nesting and to establish the top part of the hierarchy early, then let lower-level structure emerge only when needed.

2. Layer-Based (Technical) Folder Structure

Layer-based structure is the classic React setup. You get components, hooks, services, utils, types, maybe constants, and everything is sorted by technical role. It's easy to start with because every new file has an obvious bucket.

For a small MVP, this can be perfectly fine. If your app is basically one workflow with limited surface area, a clean technical split is simpler than inventing feature boundaries too early. That's one reason many teams begin with it before moving to something more domain-oriented.

Where it works and where it breaks

Layer-based folders work best when the app is still narrow. A simple booking app, internal tool, or one-core-flow prototype can live comfortably in src/components, src/hooks, and src/services for a while. The problem starts when features multiply and every task requires jumping across half the tree.

A profile change might touch:

  • components for the form
  • hooks for the mutation
  • services for the API client
  • types for the payload
  • utils for validation helpers

That structure spreads one business change across many top-level folders. It's workable, but it raises the cost of every change. If you're still deciding between patterns, this roundup of React Native best practices from AppLighter pairs well with a technical-layer starting point.

Use layer-based folders when the app is small and the team needs speed. Leave yourself a migration path before the structure hardens.

The best compromise is often layers within features. Instead of one global components folder swallowing the codebase, keep small internal layers inside auth, checkout, or workspace. That gives you the familiarity of technical separation without the long-term sprawl.

3. Screaming Architecture (Use-Case Driven)

Screaming Architecture asks a blunt question. When someone opens your repository, does the structure reveal what the product does?

If the top-level folders say components, lib, hooks, and utils, the codebase tells me it's written in React. That's not useful. If the folders say user-onboarding, checkout, order-tracking, or team-collaboration, the codebase tells me the business shape of the app. That's much more useful.

Name folders after what users do

This approach works especially well in product-heavy Expo apps where flows matter more than generic screens. An e-commerce app might use product-browsing, cart, checkout, and order-history. A SaaS app might use onboarding, workspace, billing, and settings-access.

There's a subtle difference between feature-based and use-case-driven structure. Feature-based says “profile.” Screaming Architecture often says “edit-profile” or “complete-profile.” One names a domain. The other names a user task. For teams that organize work around user journeys, the second is often clearer.

The trade-off is granularity. If you split too aggressively by workflow, shared domain logic gets duplicated or scattered. Keep the major folders tied to durable user journeys, then group supporting logic underneath.

  • Good fit for apps with clear flows like signup, checkout, publishing, or moderation
  • Bad fit for tiny apps where use cases are too small to justify their own folders
  • Best result when sprint planning and folder names use the same language

A use-case-driven tree also helps product managers and designers go through the repo during reviews. They won't know where hooks/useCheckoutSession.ts lives, but they'll understand checkout/.

4. Monorepo with Workspace Separation

Once you have more than one app surface, a single Expo folder starts carrying too much responsibility. Mobile, web, shared UI, API contracts, and backend helpers all end up mixed together. That's when a monorepo starts paying for itself.

A clean monorepo gives each concern a home. I like apps for deployable apps, packages for reusable libraries, and services for backend or edge code. The shape is obvious, and that matters more than clever naming.

A professional desk setup with three cardboard document organizers on a wooden surface with a laptop nearby.A professional desk setup with three cardboard document organizers on a wooden surface with a laptop nearby.

A practical workspace layout

A typical setup might look like this:

  • apps/mobile for the Expo app
  • apps/web for a React web app or admin portal
  • packages/ui for shared components
  • packages/types for contracts and domain models
  • services/api for Hono endpoints or server-side logic

Discipline beats tooling. Turbo, Nx, and pnpm workspaces can all manage the plumbing, but they won't fix fuzzy boundaries. Shared code should move to packages only when it's genuinely shared, not when someone wants to avoid deciding where a file belongs. AppLighter's comparison of React Native boilerplates for 2026 is useful if you're evaluating starter structures rather than assembling all of this yourself.

When monorepo discipline matters

Adobe's AEM guidance recommends keeping assets per folder in the 500 to 1,000 range because performance degrades once a single folder grows beyond 1,000 items, due to repository loading behavior (Adobe AEM folder structure best practices). That's an asset-management benchmark, not a React Native one, but the operational lesson carries over. Large, crowded directories become painful to access and maintain.

Here's a useful walkthrough if you want to visualize how shared packages and app workspaces fit together:

Monorepos fail when teams treat them like a dumping ground. They work when each workspace has a clear reason to exist, a README, and import boundaries that people enforce.

5. Modular Architecture with Clear Public APIs

Folders shouldn't just store files. They should define boundaries. That's the difference between “organized” and “architected.”

A good module exposes a small public API and hides the rest. In practice, that usually means an index.ts at the module root exports the parts other modules are allowed to use. Everything else stays internal. If another developer has to reach into auth/internal/session/refresh-token.ts, the module boundary has already failed.

Hide internals on purpose

A solid auth module might export only AuthProvider, useAuth, and a few auth types. The rest stays private. The same applies to a UI component package. Button should be public. Internal style variants, composition helpers, and implementation details shouldn't leak.

That gives you two big wins. Refactors get safer, and imports get cleaner. More importantly, your folder structure starts expressing contracts instead of just file locations.

A complex wooden puzzle structure sits on a table, representing the concept of modular API development.A complex wooden puzzle structure sits on a table, representing the concept of modular API development.

Boundary rule: Import from the module root, not from its internals. If the root doesn't export what you need, fix the module. Don't tunnel around it.

I've found this matters even more when teams use AI-assisted coding. Generated files often land in the right broad area but bypass the intended module contract. That's one reason a public API layer matters in modern Expo stacks with Cursor or Claude Code in the loop. If you want a broader architecture view, AppLighter's guide to mobile app architecture complements this pattern well.

This approach also plays nicely with backend-adjacent modules and service clients, including an AI-driven no-code backend platform, where keeping a narrow integration surface reduces churn when APIs evolve.

6. Flat Structure with Progressive Nesting

Over-structuring is one of the most common early mistakes. Developers create a grand architecture before the app has earned it. The result looks polished, but the folders are mostly placeholders.

A flatter structure is often better at the start. Keep the root simple, use broad buckets sparingly, and introduce deeper nesting only when a folder becomes noisy or a feature becomes real. This is the practical middle ground between chaos and premature abstraction.

Start simple, then split with intent

A data organization methodology published in the Data Science Journal outlines a useful sequence: collect file types, sort them into logical clusters, map the hierarchy, and document naming schemes. The same guidance recommends shallow hierarchies and warns against going past six nested folders, while also suggesting an inbox folder and a dormant zzz folder for unclassified or inactive material (Data Science Journal data organization method).

That translates well to app code and project files. Early in a product, it's fine to keep components, hooks, services, types, and config close to the root. Later, when components becomes a junk drawer or services mixes unrelated domains, split it deliberately.

A couple of practical adaptations work well for Expo teams:

  • Use an inbox area for temporary generated files, rough utilities, or AI-created fragments that haven't earned a permanent home.
  • Use a zzz area for deprecated screens, old experiments, or dormant migrations you're keeping briefly before deletion.
  • Promote only stable patterns into deeper structure after the same shape appears multiple times.

This keeps the tree honest. The structure grows because the code demanded it, not because a diagram looked impressive.

7. Type-Safety First with Centralized Type Definitions

In TypeScript-heavy apps, types aren't just support files. They define the seams between screens, services, APIs, and shared packages. If the types are messy, the folder structure usually is too.

That doesn't mean every type belongs in one giant types.ts. It means the codebase should make domain contracts easy to find. user, billing, workspace, and notifications should each have clear type ownership, whether that sits in a shared package or within a feature module.

Types should shape the codebase

Many Expo projects clean up quickly. A packages/types workspace in a monorepo, or a well-organized src/types area in a single app, can prevent duplicated contracts and drift between frontend and backend. Shared API response shapes, navigation params, and domain models become easier to audit.

I prefer grouping exported types by domain, not alphabetically. user.types.ts, billing.schema.ts, or workspace-contracts.ts tells you more than a giant directory full of disconnected names. Keep runtime validation close to those contracts too, especially if the app consumes third-party APIs or edge functions.

Types should travel with the business domain they describe. Utility types can stay global. Domain models shouldn't.

This structure also helps when AI tools generate code. Inconsistent file naming and “unknown” outputs are becoming a real maintenance problem in modern coding workflows. General folder advice rarely addresses that directly. The better answer is to force generated code back through clear domain types and approved module entry points, instead of letting random files define your contracts.

8. Environment-Aware Structure with Config Separation

Environment handling gets messy fast in Expo apps. You've got local development, preview builds, staging, production, maybe web-specific behavior, and sometimes separate analytics or payment settings per target. If config is scattered across screens, hooks, and services, bugs become hard to trace.

The fix is boring and effective. Put environment and config concerns in one place, make imports flow through that one place, and keep secrets out of application code.

Config belongs in one place

A good structure usually includes a config or env folder with files like env.ts, features.ts, api.ts, and analytics.ts. The app imports from those modules, not directly from process.env all over the codebase. That gives you one validation layer, one naming convention, and one place to update when build settings change.

This also works well with Expo's app configuration and EAS build profiles. Your routing code and UI components shouldn't care where the API base URL came from. They should only receive a typed config object.

One nuance many generic guides miss is that fast-moving MVPs don't always benefit from rigid, prebuilt folder templates. Extensis highlights the importance of structuring around incoming files and how they're processed, which points to a more fluid top level for evolving projects rather than a fixed departmental split (Extensis organized folder structure tips). For modern Expo prototypes, that often means config stays stable while feature folders evolve.

Use environment-aware structure to isolate change. Config changes often. Business logic shouldn't.

8-Point Folder Structure Best-Practices Comparison

Approach🔄 Implementation complexity⚡ Resource requirements & efficiency📊 Expected outcomes⭐ Key advantages💡 Ideal use cases
Feature-Based (Domain-Driven) Folder Structure🔄 Medium, needs clear feature boundaries and discipline⚡ Moderate, some early duplication, scales well with teams📊 High modularity and easier feature-focused work⭐ Encapsulated features; straightforward code-splitting and lazy loading💡 Startup MVPs and growth-stage apps where features evolve rapidly
Layer-Based (Technical) Folder Structure🔄 Low, simple, predictable technical separation⚡ Low, minimal tooling and overhead for small projects📊 Works well for small apps; can become brittle as size grows⭐ Familiar and easy to understand for newcomers💡 Proof-of-concepts and small prototype apps (<10 core features)
Screaming Architecture (Use-Case Driven)🔄 Medium-High, requires mapping user journeys upfront⚡ Moderate, business-aligned structure reduces rework later📊 Clear product intent and easier cross-functional communication⭐ Makes application purpose obvious; aligns with user stories💡 Product teams and startups focused on user workflows and prioritization
Monorepo with Workspace Separation🔄 High, tooling, CI/CD and workspace boundaries required⚡ High efficiency at scale, shared code, atomic commits; larger repo cost📊 Strong cross-platform consistency and easier large-scale refactors⭐ Single source of truth for shared packages; simplified dependency management💡 Cross-platform Expo apps, full-stack startups with shared libraries
Modular Architecture with Clear Public APIs🔄 Medium, planning and enforcing module APIs needed⚡ Moderate, linting and export discipline, good for testing📊 Safer refactoring and clearer inter-module contracts⭐ Prevents tight coupling; clear public interfaces improve collaboration💡 Team-based projects requiring maintainability and extensibility
Flat Structure with Progressive Nesting🔄 Low, start flat and introduce nesting when necessary⚡ Very low initial overhead; refactoring costs later📊 Fast prototyping; risk of disorder as project grows⭐ Minimal setup and fast project start💡 Solo developers and early-stage MVPs for rapid iteration
Type-Safety First with Centralized Type Definitions🔄 Medium, requires type generation and careful organization⚡ Moderate, tooling (OpenAPI, Zod) and ongoing maintenance📊 Strong compile-time guarantees and reduced runtime errors⭐ Single source of truth for domain models; excellent IDE/refactor support💡 Full-stack TypeScript projects and API-driven apps needing strict safety
Environment-Aware Structure with Config Separation🔄 Medium-High, careful build and environment config management⚡ Moderate, env tooling and CI/CD discipline required📊 Safer multi-environment deployments and clearer config ownership⭐ Enables feature flags, staged rollouts, and environment-specific builds💡 Production apps deployed across dev/staging/prod and multiple platforms

From Blueprint to Build Your Next Actionable Step

The best folder structure isn't the one that looks smartest in a screenshot. It's the one your team can keep using after the app gets bigger, the roadmap changes, and new contributors start touching the code. That's why I rarely recommend choosing a single pattern in isolation.

For most modern Expo projects, the strongest default is a hybrid. Start with feature-based folders because they map cleanly to product work. Put that inside a monorepo when you have more than one app surface or a meaningful amount of shared code. Inside those features and packages, enforce modular public APIs so developers import from stable boundaries instead of digging through internals. Then add centralized types and config separation early, before drift becomes normal.

That combination solves different classes of problems. Feature folders reduce hunting. Monorepos reduce duplication across app surfaces. Public APIs make refactoring safer. Type-first organization keeps contracts visible. Config separation keeps environments from leaking everywhere. None of these choices are trendy on their own. They're operationally useful.

A few practical decisions make a bigger difference than most architecture debates. Keep the tree shallow. Keep top-level folders limited and obvious. Don't let shared become a junk drawer. Don't add subfolders until the code earns them. Don't expose internal files just because imports are convenient. And don't let AI-generated output bypass the same structure rules human contributors follow.

If you're building an MVP, resist the urge to design an enterprise-grade tree on day one. Start simple, but not sloppy. Pick a primary organizing model, usually feature-driven or use-case-driven, and then define the guardrails that will still make sense once the app grows. That means naming conventions, a clear root layout, a policy for shared code, and a rule for where generated or temporary files go.

If you're already in a messy codebase, don't try to fix everything in one refactor. Choose one boundary to improve first. Move a fragile area like auth, onboarding, or billing into a cleaner module. Add a root index.ts public API. Pull environment reads into config. Create a better type contract. Once one part of the tree gets easier to work in, the rest usually follows.

If you'd rather skip the blank-page architecture work and start from a production-minded structure, AppLighter is worth a serious look. It gives you an opinionated Expo foundation with the important pieces already wired together, which is often the fastest route to a codebase that still feels sane months later.


If you want a production-ready Expo foundation instead of hand-assembling folders, boundaries, config, auth, and shared packages from scratch, AppLighter gives you a structured starting point built for shipping real mobile apps faster. It combines Expo, Vibecode DB with a Supabase adapter, Hono with TypeScript, authentication, navigation, state management, and AI-assisted development tooling in one opinionated starter kit, so you can spend less time debating folder layout and more time building the product.

Stay Updated on the Latest UI Templates and Features

Be the first to know about new React Native UI templates and kits, features, special promotions and exclusive offers by joining our newsletter.