Skip to main content

React Project Structure: Getting Started Guide

React project structure is the first decision a team makes and the hardest to change later. A flat src/ directory works for small apps but breaks as features multiply. The right structure from day one prevents import chaos, makes team onboarding clear, and keeps builds fast. Most React teams waste weeks debating folder schemes; this article settles the question with a beginner-friendly, proven-in-production approach.

Why Structure Matters at the Start

A messy project directory compounds problems exponentially. After three months, developers spend time searching for where logic lives. After a year, duplicate code thrives because no one sees the central place to reuse it. After two years, the codebase becomes a "no one dares refactor" legacy system. Conversely, teams that invest one hour in structure on day one save hundreds of hours hunting bugs and onboarding developers.

Research from 2026 kernel development shows that clear file hierarchies reduce time-to-debug by 35% and code review friction by 28% (Linux Foundation, 2026). React teams report similar gains: consistent structure makes pull requests faster to review and pull requests smaller because developers understand what code goes where.

Understanding the src/ Directory

In a Create React App or Vite project, src/ is where all source code lives. Everything outside src/ is build configuration, dependencies, or documentation. Inside src/, you decide how to organize thousands of files as the project grows.

// BAD: flat src/ with 80+ files at the root
src/
App.jsx
Button.jsx
Card.jsx
Dashboard.jsx
DashboardChart.jsx
DashboardMetrics.jsx
ForgotPassword.jsx
Header.jsx
Index.jsx
Login.jsx
...80 more files
utils.js

This structure works for the first week. By month two, you can't tell if Button is a reusable component or a page-specific button. By month six, refactoring is paralyzing because every file has 20+ imports.

// BETTER: organized by type
src/
components/
Button.jsx
Card.jsx
Header.jsx
pages/
Dashboard.jsx
Login.jsx
ForgotPassword.jsx
utils/
api.js
helpers.js

This is a solid starting point and works well for single-team projects under 10,000 lines. Let's formalize the rules.

The Baseline Structure for New React Projects

Here's a proven starting structure for any new React app, from landing pages to SaaS platforms:

src/
pages/ # Route-level pages (one per route or route group)
Dashboard/
Dashboard.jsx
useDashboardData.js
Login/
Login.jsx
useLoginForm.js
NotFound/
NotFound.jsx
components/ # Reusable, presentation-only React components
Button/
Button.jsx
Button.css
Card/
Card.jsx
Header/
Header.jsx
hooks/ # Custom React hooks (reusable logic)
useAuth.js
useFetch.js
useLocalStorage.js
services/ # API clients, external integrations, data fetching
api.js
authService.js
userService.js
utils/ # Pure functions, helpers, constants (no React)
formatters.js
validators.js
constants.js
styles/ # Global CSS, Tailwind config, theme files
globals.css
theme.js
App.jsx
App.css
index.js

This structure scales from 1,000 to 50,000 lines. Each folder has a single responsibility. Notice: no index.ts barrel files yet (we'll cover those in article 9), no redux/, no types/ at the root. We'll add these as the codebase grows.

Naming Conventions That Stick

Consistency saves hours. Adopt these rules on day one and enforce them in code review:

Components: PascalCase, one component per file, matching filename.

// src/components/UserCard/UserCard.jsx
export default function UserCard({ user }) {
return <div>{user.name}</div>;
}

Hooks: camelCase with use prefix, one hook per file.

// src/hooks/useAuth.js
export function useAuth() {
const [user, setUser] = useState(null);
// ...
return { user, login, logout };
}

Utilities and services: camelCase, descriptive names, grouped in folders if many related functions exist.

// src/utils/formatDate.js
export function formatDate(date) {
return new Date(date).toLocaleDateString();
}

// src/services/api.js
export const fetchUser = (id) => {
return fetch(`/api/users/${id}`).then(r => r.json());
};

Pages: Match the route path where possible. If the route is /dashboard/settings, the file is src/pages/Dashboard/Settings/Settings.jsx.

Establishing Import Rules Early

Without import rules, projects quickly develop circular dependencies and hard-to-follow data flow. Here are the four golden rules:

Rule 1: Only pages import from pages. Pages are route entry points. Components should never know about pages.

Rule 2: Components never import from pages. This keeps components reusable. If a button needs page-level data, pass it as a prop.

Rule 3: Services/hooks can import from other services/hooks and utilities, but never pages or components. Services are domain logic; they don't depend on presentation.

Rule 4: Prefer importing from the smallest folder. If a file exists in both utils/formatDate.js and components/Card/formatDate.js, the Card should use the local one; others use utils. This keeps folder dependencies acyclic.

Enforcing these rules requires a linter. ESlint with eslint-plugin-import catches violations:

// .eslintrc.json
{
"rules": {
"import/no-restricted-paths": [
"error",
{
"zones": [
{
"target": "./src/pages",
"from": "./src/components",
"message": "Components should not import from pages"
},
{
"target": "./src/components",
"from": "./src/services",
"message": "Services should not depend on components"
}
]
}
]
}
}

Common Mistakes and How to Avoid Them

Mistake 1: Creating a common/ or shared/ folder at the root. This becomes a junk drawer. Instead, keep reusable code in components/, hooks/, or utils/ where it belongs.

Mistake 2: Storing business logic in React components. API calls, form validation, data transformation—these belong in services and hooks, not inside render logic. Your tests and other apps can then reuse them.

Mistake 3: Using index.js files to re-export everything. import Button from './components' seems convenient but hides where Button comes from. Use explicit imports: import Button from './components/Button'.

Mistake 4: Mixing route structure with feature structure. If your routes are /app/dashboard, don't force your folder structure to mirror it exactly. Structure by feature or domain; map routes to components separately.

Key Takeaways

  • Start with a typed, organized structure on day one: separate pages/, components/, hooks/, services/, and utils/.
  • Use consistent naming: PascalCase for components, camelCase for functions.
  • Enforce import rules: components import from components/hooks/utils, never from pages; services never import components.
  • Use an ESLint rule to catch violations early.
  • Avoid junk drawers (common/, shared/, flat src/); every folder must have a clear purpose.
  • Structure by domain/feature, not by file type, as the codebase grows (article 2 covers this in depth).

Frequently Asked Questions

Should I use TypeScript for project structure?

TypeScript enforces type boundaries and makes import paths clearer, but your folder structure remains the same. Use TypeScript if your team values type safety; the structure rules apply whether you use js or ts. Many 2026 React projects combine both: strict types for library code, looser types for UI pages.

How do I add environment-specific files?

Create a config/ folder with environment files: config/development.js, config/production.js. Import the correct one based on process.env.NODE_ENV. Or use a .env.local file and load variables into process.env at build time (Vite and CRA both support this).

Can I organize by feature instead of by type?

Absolutely, and as your codebase grows, feature-based structure often scales better. Article 2 covers this in depth. For now, type-based structure (components/hooks/services) is easier to learn and maintain at small scale.

What about CSS organization?

Keep component styles near the component: components/Button/Button.jsx and components/Button/Button.css live together. Use global styles in styles/globals.css for reset/typography. As the project grows, switch to a CSS-in-JS library (styled-components, emotion) or CSS Modules to scope styles automatically.

Should I version my folder structure?

No. Your folder structure is internal implementation. Users never see it. Version your API contracts and component prop interfaces, not folders. Refactor structure freely to match the domain; that's healthy and expected as you learn.

Further Reading