Project Structure
Project structure should help developers find code, understand ownership, and make changes without touching unrelated areas.
There is no perfect folder layout for every React app. Good structure depends on app size, team size, routing, data flow, and product boundaries.
Start Simple
Small apps can use a simple layout.
src/
components/
pages/
hooks/
lib/
styles/
App.jsxThis is fine when the app is small and there are few features.
Do not over-engineer a prototype.
When Structure Starts to Hurt
Flat technical folders can become painful as the app grows.
components/
UserTable.jsx
ProjectTable.jsx
BillingForm.jsx
LessonCard.jsx
CourseSidebar.jsx
hooks/
useUsers.js
useProjects.js
useBilling.js
useLessons.jsThe problem is not the folder names. The problem is that code for one feature is scattered across the project.
Feature-Oriented Structure
A feature-oriented structure groups code by product area.
src/
app/
routes/
providers/
features/
courses/
components/
hooks/
api/
types/
billing/
components/
hooks/
api/
types/
shared/
components/
hooks/
lib/This makes ownership clearer.
If you are changing course progress, you start in features/courses.
Shared Code
shared should contain code that is truly reused across features.
Good shared code:
- design system components
- formatting helpers
- generic hooks
- API client primitives
- date and currency utilities
Avoid moving code to shared just because two files currently use it. Wait until the abstraction is stable enough.
Naming Matters
Use names that communicate product meaning.
Prefer:
features/course-progress/
features/checkout/
features/lesson-player/Over vague buckets:
features/misc/
features/common/
features/new/Vague folders become dumping grounds.
Import Boundaries
Structure is only useful if imports respect it.
Example rule:
features/billing can import:
shared/*
features/billing/*
features/billing should not import:
features/courses/internal/*Some teams enforce this with lint rules or path aliases.
Co-Locating Tests
Tests can live near the code they verify.
features/courses/
components/
CourseCard.jsx
CourseCard.test.jsxCo-location makes ownership obvious and lowers the cost of updating tests when behavior changes.
Common Mistakes
- Creating many folders before the app has real complexity.
- Keeping everything in
componentsforever. - Using
sharedas a junk drawer. - Allowing deep imports into another feature's internals.
- Organizing only by file type and ignoring product ownership.
Edge Case
A design system button belongs in shared or a design system package.
A StartLessonButton probably belongs in the course feature because it contains course-specific behavior.
What is the main benefit of feature-oriented structure in a growing React app?
Practical Challenge
Take a flat React project and choose one feature.
Move only that feature's:
- components
- hooks
- API functions
- tests
- types
Write down what should remain shared and what should stay private to the feature.
Recap
Good project structure optimizes for finding, changing, and owning code.
Start simple, group by feature as complexity grows, and keep shared code truly shared.