As your React application grows, organization becomes critical. Where do you put components? How do you name files? What folder structure should you use? Good organization makes your code easier to understand, maintain, and scale. In this lesson, you'll learn proven patterns for organizing React projects, from small apps to large production codebases. Let's build maintainable React applications! š
Why Organization Matters
Poor organization leads to:
- Difficulty finding files
- Duplicate code
- Inconsistent patterns
- Hard to onboard new developers
- Slower development
- Technical debt
Good organization provides:
- Clear structure everyone understands
- Easy to find and modify code
- Reusable components
- Faster development
- Easier testing
- Better scalability
File Naming Conventions
Component Files
ā
Recommended: PascalCase
Button.jsx
UserProfile.jsx
ProductCard.jsx
NavigationMenu.jsx
ā
Also acceptable: PascalCase with extension
Button.tsx
UserProfile.tsx
ā
For pages/routes: PascalCase or kebab-case
HomePage.jsx or home-page.jsx
AboutPage.jsx or about-page.jsx
ā Avoid:
button.jsx // lowercase (hard to distinguish from non-components)
user-profile.jsx // kebab-case for components (inconsistent)
userProfile.jsx // camelCase (not standard for components)Non-Component Files
ā
Utilities and helpers: camelCase
formatDate.js
calculateTotal.js
validateEmail.js
ā
Hooks: camelCase with "use" prefix
useAuth.js
useFetch.js
useLocalStorage.js
ā
Constants: UPPER_SNAKE_CASE
API_ENDPOINTS.js
COLORS.js
CONFIG.js
ā
Types/Interfaces (TypeScript): PascalCase
User.types.ts
Product.interface.ts
types.ts
ā
Styles: Match component name
Button.css
Button.module.css
Button.styles.jsš” Naming Convention Rule
Simple rule:
⢠Components ā PascalCase
⢠Everything else ā camelCase
⢠Constants ā UPPER_SNAKE_CASE
Consistency matters more than the specific convention!
Folder Structure Patterns
Pattern 1: Feature-Based Structure (Recommended)
src/
āāā features/
ā āāā auth/
ā ā āāā components/
ā ā ā āāā LoginForm.jsx
ā ā ā āāā SignupForm.jsx
ā ā ā āāā PasswordReset.jsx
ā ā āāā hooks/
ā ā ā āāā useAuth.js
ā ā ā āāā useLogin.js
ā ā āāā services/
ā ā ā āāā authService.js
ā ā āāā utils/
ā ā ā āāā validation.js
ā ā āāā index.js
ā ā
ā āāā products/
ā ā āāā components/
ā ā ā āāā ProductCard.jsx
ā ā ā āāā ProductList.jsx
ā ā ā āāā ProductDetail.jsx
ā ā āāā hooks/
ā ā ā āāā useProducts.js
ā ā āāā index.js
ā ā
ā āāā user/
ā āāā components/
ā ā āāā UserProfile.jsx
ā ā āāā UserSettings.jsx
ā āāā hooks/
ā ā āāā useUser.js
ā āāā index.js
ā
āāā components/ # Shared/reusable components
ā āāā ui/
ā ā āāā Button.jsx
ā ā āāā Input.jsx
ā ā āāā Modal.jsx
ā ā āāā Card.jsx
ā āāā layout/
ā āāā Header.jsx
ā āāā Footer.jsx
ā āāā Sidebar.jsx
ā
āāā hooks/ # Shared hooks
ā āāā useLocalStorage.js
ā āāā useDebounce.js
ā āāā useWindowSize.js
ā
āāā utils/ # Shared utilities
ā āāā formatDate.js
ā āāā api.js
ā āāā constants.js
ā
āāā pages/ # Page components
ā āāā HomePage.jsx
ā āāā AboutPage.jsx
ā āāā DashboardPage.jsx
ā
āāā App.jsx
āāā index.js
Benefits:
ā
Related code grouped together
ā
Easy to find feature-specific code
ā
Clear separation of concerns
ā
Easy to add/remove features
ā
Scales well for large appsPattern 2: Type-Based Structure
src/
āāā components/
ā āāā Button.jsx
ā āāā Card.jsx
ā āāā Header.jsx
ā āāā Footer.jsx
ā āāā LoginForm.jsx
ā āāā ProductCard.jsx
ā āāā UserProfile.jsx
ā
āāā hooks/
ā āāā useAuth.js
ā āāā useFetch.js
ā āāā useProducts.js
ā
āāā pages/
ā āāā HomePage.jsx
ā āāā ProductsPage.jsx
ā āāā ProfilePage.jsx
ā
āāā services/
ā āāā authService.js
ā āāā apiService.js
ā
āāā utils/
ā āāā formatDate.js
ā āāā validation.js
ā
āāā App.jsx
āāā index.js
Good for:
ā
Small to medium apps
ā
Simple projects
ā
Learning/prototypes
Challenges:
ā Hard to scale
ā Mixing unrelated code
ā Difficult to find related filesPattern 3: Hybrid Structure (Best for Most Apps)
src/
āāā features/ # Feature-specific code
ā āāā auth/
ā ā āāā LoginForm.jsx
ā ā āāā useAuth.js
ā ā āāā authService.js
ā ā
ā āāā products/
ā āāā ProductList.jsx
ā āāā ProductCard.jsx
ā āāā useProducts.js
ā
āāā components/ # Shared components only
ā āāā Button.jsx
ā āāā Input.jsx
ā āāā Modal.jsx
ā
āāā hooks/ # Shared hooks only
ā āāā useDebounce.js
ā āāā useLocalStorage.js
ā
āāā layouts/ # Page layouts
ā āāā MainLayout.jsx
ā āāā DashboardLayout.jsx
ā
āāā pages/ # Route components
ā āāā HomePage.jsx
ā āāā DashboardPage.jsx
ā āāā NotFoundPage.jsx
ā
āāā services/ # API services
ā āāā api.js
ā
āāā utils/ # Utilities
ā āāā formatDate.js
ā āāā constants.js
ā
āāā App.jsx
āāā index.js
ā
Best of both worlds
ā
Clear separation
ā
Easy to navigate
ā
Scales wellComponent File Organization
Single File Component
// Simple components in one file
import React from 'react'
import './Button.css'
function Button({ children, variant = 'primary', onClick, disabled }) {
return (
<button
className={`btn btn-${variant}`}
onClick={onClick}
disabled={disabled}
>
{children}
</button>
)
}
export default Button
// Good for: Simple, self-contained componentsComponent with Folder
ProductCard/
āāā ProductCard.jsx # Main component
āāā ProductCard.module.css
āāā ProductCard.test.jsx # Tests
āāā useProductCard.js # Component-specific hook
āāā index.js # Public API
// index.js
export { default } from './ProductCard'
export { useProductCard } from './useProductCard'
Good for:
ā
Complex components
ā
Components with tests
ā
Components with styles
ā
Components with hooksFeature Module Structure
auth/
āāā components/
ā āāā LoginForm/
ā ā āāā LoginForm.jsx
ā ā āāā LoginForm.module.css
ā ā āāā LoginForm.test.jsx
ā ā
ā āāā SignupForm/
ā āāā SignupForm.jsx
ā āāā SignupForm.test.jsx
ā
āāā hooks/
ā āāā useAuth.js
ā āāā useLogin.js
ā
āāā services/
ā āāā authService.js
ā
āāā utils/
ā āāā validation.js
ā
āāā types.ts # TypeScript types
āāā constants.js # Feature constants
āāā index.js # Public exports
// index.js - Export only what other features need
export { LoginForm, SignupForm } from './components'
export { useAuth } from './hooks'
export { login, logout } from './services/authService'Component Categories
1. Page Components
// pages/DashboardPage.jsx
import DashboardLayout from '../layouts/DashboardLayout'
import { UserStats, RecentActivity, QuickActions } from '../features/dashboard'
function DashboardPage() {
return (
<DashboardLayout>
<h1>Dashboard</h1>
<UserStats />
<RecentActivity />
<QuickActions />
</DashboardLayout>
)
}
export default DashboardPage
// Characteristics:
// - Corresponds to routes
// - Composes other components
// - Minimal logic
// - Usually in pages/ folder2. Layout Components
// layouts/MainLayout.jsx
import Header from '../components/layout/Header'
import Footer from '../components/layout/Footer'
import Sidebar from '../components/layout/Sidebar'
function MainLayout({ children }) {
return (
<div className="main-layout">
<Header />
<div className="content-wrapper">
<Sidebar />
<main className="main-content">
{children}
</main>
</div>
<Footer />
</div>
)
}
export default MainLayout
// Characteristics:
// - Wraps other components
// - Defines page structure
// - Usually receives children
// - Shared across pages3. Feature Components
// features/products/ProductList.jsx
import { useProducts } from './hooks/useProducts'
import ProductCard from './ProductCard'
import LoadingSpinner from '../../components/LoadingSpinner'
function ProductList({ category }) {
const { products, loading, error } = useProducts(category)
if (loading) return <LoadingSpinner />
if (error) return <div>Error: {error}</div>
return (
<div className="product-list">
{products.map(product => (
<ProductCard key={product.id} product={product} />
))}
</div>
)
}
export default ProductList
// Characteristics:
// - Feature-specific logic
// - May fetch data
// - Business logic
// - In features/ folder4. UI/Shared Components
// components/ui/Button.jsx
function Button({
children,
variant = 'primary',
size = 'medium',
onClick,
disabled
}) {
return (
<button
className={`btn btn-${variant} btn-${size}`}
onClick={onClick}
disabled={disabled}
>
{children}
</button>
)
}
export default Button
// Characteristics:
// - Generic/reusable
// - No business logic
// - Presentation only
// - Used across features
// - In components/ folderImport/Export Patterns
Named vs Default Exports
// ā
Default export - Good for main component
// Button.jsx
function Button() { }
export default Button
// Usage
import Button from './Button'
// ā
Named exports - Good for multiple exports
// utils.js
export function formatDate() { }
export function formatCurrency() { }
// Usage
import { formatDate, formatCurrency } from './utils'
// ā
Hybrid - Component + utilities
// ProductCard.jsx
function ProductCard() { }
export default ProductCard
export function formatPrice() { }
export const CURRENCY = 'USD'
// Usage
import ProductCard, { formatPrice, CURRENCY } from './ProductCard'
// ā Avoid mixing patterns inconsistently
// Pick one pattern and stick to it!Index Files (Barrel Exports)
// components/ui/index.js
export { default as Button } from './Button'
export { default as Input } from './Input'
export { default as Modal } from './Modal'
export { default as Card } from './Card'
// Usage - Clean imports!
import { Button, Input, Modal } from '../components/ui'
// Instead of:
import Button from '../components/ui/Button'
import Input from '../components/ui/Input'
import Modal from '../components/ui/Modal'
// ā ļø Warning: Can affect tree-shaking
// Use with caution in large apps
// Better for features:
// features/auth/index.js
export { LoginForm } from './components/LoginForm'
export { SignupForm } from './components/SignupForm'
export { useAuth } from './hooks/useAuth'
// Now other features import from feature root:
import { LoginForm, useAuth } from '../features/auth'Absolute Imports
// jsconfig.json or tsconfig.json
{
"compilerOptions": {
"baseUrl": "src"
}
}
// Before: Relative imports
import Button from '../../../components/ui/Button'
import { useAuth } from '../../../hooks/useAuth'
// After: Absolute imports
import Button from 'components/ui/Button'
import { useAuth } from 'hooks/useAuth'
// Or with path aliases:
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@components/*": ["src/components/*"],
"@hooks/*": ["src/hooks/*"],
"@utils/*": ["src/utils/*"],
"@features/*": ["src/features/*"]
}
}
}
// Usage:
import Button from '@components/ui/Button'
import { useAuth } from '@hooks/useAuth'
// Benefits:
// ā
Easier refactoring
// ā
More readable
// ā
Less ../ navigationOrganization Best Practices
- Start Simple, Refactor Later
Small app (< 10 components):
src/
āāā components/
āāā App.jsx
āāā index.js
Medium app (10-50 components):
src/
āāā components/
āāā hooks/
āāā utils/
āāā pages/
āāā App.jsx
Large app (50+ components):
src/
āāā features/
āāā components/
āāā hooks/
āāā utils/
āāā pages/
āāā App.jsx
Don't over-engineer early!- Co-locate Related Files
ā
Keep related files together
ProductCard/
āāā ProductCard.jsx
āāā ProductCard.css
āāā ProductCard.test.jsx
āāā useProductCard.js
ā Don't separate by type when closely related
components/
āāā ProductCard.jsx
styles/
āāā ProductCard.css
tests/
āāā ProductCard.test.jsx
hooks/
āāā useProductCard.js- Use Consistent Naming
Pick a convention and stick to it:
- Components: PascalCase
- Files: Match component name
- Folders: Match main file
- Utilities: camelCase
- Constants: UPPER_SNAKE_CASE
- One Component Per File
// ā Avoid: Multiple components in one file
function Header() { }
function Navigation() { }
function UserMenu() { }
// ā
Good: One main component
function Header() { }
// Small helper components are OK
function HeaderLink({ href, children }) { }
// ā
Better: Extract if used elsewhere
// Header.jsx
import Navigation from './Navigation'
import UserMenu from './UserMenu'
function Header() {
return (
<header>
<Navigation />
<UserMenu />
</header>
)
}- Keep Component Files Small
If component exceeds 200-300 lines, consider:
- Extracting sub-components
- Moving logic to custom hooks
- Creating utility functions
- Splitting into multiple components
- Document Complex Structures
# Project Structure
## Folder Organization
- `/features` - Feature-based modules
- `/components` - Shared/reusable components
- `/hooks` - Custom React hooks
- `/utils` - Helper functions
- `/pages` - Page components
## Naming Conventions
- Components: PascalCase (e.g., `UserProfile.jsx`)
- Hooks: camelCase with "use" prefix (e.g., `useAuth.js`)
- Utils: camelCase (e.g., `formatDate.js`)
## Import Rules
- Use absolute imports with @ aliases
- Barrel exports in feature modules
- Default exports for componentsRemember:
There's no "perfect" structure for all projects!
Choose based on:
⢠Team size and preferences
⢠Project complexity
⢠Domain requirements
⢠Future scalability needs
Consistency is more important than the specific pattern!
Key Takeaways
- Components use PascalCase, utilities use camelCase
- Feature-based structure scales better than type-based
- Hybrid approach works for most applications
- Co-locate related files (component + styles + tests)
- Use barrel exports (index.js) for clean imports
- Consider absolute imports with path aliases
- One main component per file
- Keep component files under 200-300 lines
- Separate shared components from feature components
- Start simple and refactor as you grow
- Document your structure for the team
- Consistency matters more than perfection
- Choose structure based on team and project needs
What's Next?
You now understand how to organize React projects for maintainability and scalability! You know file naming conventions, folder structures, and best practices.
In the next lesson, you'll learn about Performance Optimization:
- Using React.memo to prevent re-renders
- Code splitting with lazy loading
- Optimizing bundle size
- Profiling React applications
- Common performance patterns
Get ready to make your React apps blazing fast! ā”