Project Structure

Where Things Live in a Real React App

Project Structure

There's no one "correct" layout, but a few conventions show up again and again. Pick one and stay consistent.

4 min read Level 1/5 #react#structure#conventions
What you'll learn
  • Recognize common folder layouts
  • Know where to put components, hooks, utils, types
  • Avoid premature folder splitting

There’s no React-enforced project layout. A few conventions show up in most codebases — pick one and stick with it.

A Small App

For a starter Vite app:

src/
  components/
    Button.jsx
    Card.jsx
  pages/
    Home.jsx
    Settings.jsx
  hooks/
    useAuth.js
  lib/
    api.js
  App.jsx
  main.jsx
  • components/ — reusable UI pieces
  • pages/ (or routes/) — top-level screens
  • hooks/ — custom hooks
  • lib/ (or utils/) — plain JS helpers
  • App.jsx — top-level component, routing setup
  • main.jsx — the React entry point

A Bigger App — Feature Folders

For larger apps, group by feature instead of type:

src/
  features/
    auth/
      LoginForm.jsx
      useAuth.js
      authApi.js
    todos/
      TodoList.jsx
      TodoItem.jsx
      useTodos.js
      todosApi.js
  shared/
    components/      ← components used across features
    hooks/
    lib/
  pages/
  App.jsx

The win: when you delete a feature, you delete one folder. Files that change together live together.

File Naming

Common conventions:

  • Components: PascalCase.jsxUserCard.jsx
  • Hooks: useCamelCase.jsuseFetch.js
  • Helpers: camelCase.jsformatDate.js

Pick a casing and stay consistent. A folder full of mismatched files is its own kind of mess.

When to Split a File

Default to one component per file. Exception: tiny helper components that only one parent uses can share a file with their parent.

// In Card.jsx
function CardImage({ src }) { return <img className="card__img" src={src} />; }
function CardTitle({ children }) { return <h3 className="card__title">{children}</h3>; }

export function Card({ src, title, body }) {
  return (
    <article className="card">
      <CardImage src={src} />
      <CardTitle>{title}</CardTitle>
      <p>{body}</p>
    </article>
  );
}

The inner helpers are unexported — only Card uses them.

Don’t Premature-Optimize Folders

Three components don’t need three folders. Start flat; split when the listing gets long enough to be annoying.

Path Aliases

Add an alias in vite.config.js so deep imports look clean:

// vite.config.js
import path from "node:path";

export default {
  resolve: {
    alias: { "@": path.resolve(__dirname, "src") },
  },
};

Now import Button from "@/components/Button" instead of ../../components/Button.

Up Next

Real apps have routes. Let’s talk routing.

Routing Intro →