React File and Folder Structure: What Actually Works (And What Doesn’t)

Let me be honest with you — when I first started building React apps, my folder structure was a disaster.

Everything lived inside one components folder. Pages, API calls, helper functions, even some random CSS files I forgot to delete. It looked fine at the beginning. Two weeks later, I had no idea where anything was.

If that sounds familiar, this post is for you.

I’m not going to give you some theoretical “best practice” that nobody actually uses. I’m going to show you what works in real projects — the kind you maintain months later and still understand.

First, Let’s Talk About Why This Even Matters

Nobody cares about folder structure on day one. You’re excited, you’re building, everything’s small and manageable. The app has three components and life is good.

Then you add authentication. Then a few more pages. Then someone asks you to add a dashboard. Before you know it, you have forty files and you’re scrolling through your editor sidebar like you’re looking for your keys in a dark room.

A decent folder structure won’t make your code run faster. It won’t fix bugs. But it will stop you from losing your mind when the project grows — and every project grows.

What React Gives You Out of the Box

A standard Vite + React setup drops you here:

my-react-app/
├── public/
├── src/
│   ├── App.jsx
│   ├── main.jsx
│   └── index.css
├── package.json
└── vite.config.js

Totally fine to start. But you’ll outgrow this faster than you think.

The Structure I Actually Recommend

After working on several projects — some mine, some with teams — this is the layout I keep coming back to:

src/
├── assets/
├── components/
├── pages/
├── layouts/
├── hooks/
├── services/
├── utils/
├── context/
├── routes/
├── styles/
├── App.jsx
└── main.jsx

Let me walk through each one, but I’ll try to keep it real instead of just listing definitions.

assets/

Logos, images, SVG icons, fonts. Static stuff that doesn’t change based on what the user does.

assets/
├── images/
├── icons/
├── fonts/

The main reason to have this is simple — you don’t want to hunt for a logo file that someone dropped inside a random component folder three months ago. Ask me how I know.

components/

This is for UI pieces you reuse in more than one place. Buttons, input fields, modals, cards, spinners.

components/
├── Button/
│   ├── Button.jsx
│   └── Button.css
├── Modal/
├── Loader/

The test I use: if I can drop this into a completely different project and it still makes sense on its own, it belongs here.

One thing I’d suggest — give each component its own folder instead of dumping all .jsx files in one flat list. It makes co-locating the CSS or tests much cleaner.

pages/

Pages are the screens. Home, About, Login, Dashboard — each one usually maps to a route.

pages/
├── Home/
├── About/
├── Login/
└── Dashboard/

The difference between pages and components trips a lot of people up early on. Think of it this way — a Button is a component. The page that uses that button is a page. Pages are never really reused. Components are.

layouts/

This one’s easy to skip when you’re starting out, but you’ll wish you had it later.

Layouts wrap your pages. Your main site might have a header, sidebar, and footer on every page. Instead of copy-pasting that into every page file, you define it once here:

layouts/
├── MainLayout.jsx
└── AdminLayout.jsx

If you ever have a public-facing site and an admin panel, this folder alone saves you from a lot of headaches.

hooks/

Custom hooks are one of React’s best features and also one of the most underused by beginners.

hooks/
├── useFetch.js
├── useAuth.js
└── useLocalStorage.js

If you find yourself writing the same useEffect and useState pattern in three different components, that’s a hook waiting to be extracted. Putting them all here means anyone on the team can find and reuse them without duplicating logic.

services/

This is where API calls live. Not inside your components — here.

services/
├── authService.js
├── productService.js
└── userService.js

js

// services/userService.js
export const getUsers = () => {
  return axios.get('/api/users');
};

I’ve seen components that are 300 lines long because the API logic was mixed right in with the JSX. It’s painful to read and painful to test. Keeping data-fetching logic in services/ means your components stay focused on what they should be doing — rendering UI.

utils/

Helper functions that don’t really belong anywhere specific.

utils/
├── formatDate.js
├── validateEmail.js
└── truncateText.js

These are the small, reusable functions you find yourself writing over and over across different projects. Date formatting, string manipulation, basic math — stuff like that. Put it here once, import it everywhere.

context/

If you’re using React Context for global state — user auth, theme, language — keep your context files here.

context/
├── AuthContext.jsx
└── ThemeContext.jsx

Nothing fancy. Just a dedicated home so you’re not digging through component files looking for where you defined the auth provider.


routes/

Route configuration. All of it, in one file.

routes/
└── AppRoutes.jsx

jsx

<Route path="/" element={<Home />} />
<Route path="/dashboard" element={<Dashboard />} />
<Route path="/login" element={<Login />} />

When you have 15 routes and they’re all defined inside App.jsx, that file turns into a mess. Pull routes out early — you’ll thank yourself later.

styles/

Global CSS goes here. Things like CSS variables, base resets, typography defaults.

styles/
├── global.css
├── variables.css
└── theme.css

Component-specific styles can stay next to the component. But anything that affects the whole app belongs in here.

When Your Project Gets Really Big

The structure above works well up to a certain size. Once you’re dealing with multiple major features — authentication, e-commerce, dashboard, admin panel — a lot of teams switch to a feature-based approach instead.

It looks like this:

src/
├── features/
│   ├── auth/
│   │   ├── components/
│   │   ├── pages/
│   │   ├── hooks/
│   │   └── services/
│   ├── products/
│   └── dashboard/

The logic here is that when you’re working on the auth feature, everything you need — the components, the API calls, the hooks — is in one place. You’re not jumping between five top-level folders just to make one feature change.

For small projects, this structure feels like overkill. For big ones, it’s genuinely the better call.

Mistakes I’ve Made (So You Don’t Have To)

Putting everything in components/ — This is the most common one. Pages, hooks, API calls, random helper functions — all crammed in one folder. It makes sense for about a week, then becomes impossible to navigate.

Going too deep with nesting — I went through a phase where I thought more folders meant better organization. Ended up with paths like components/ui/forms/inputs/text/. At some point you’re just making your own life harder. Flat is usually better than deep.

Writing API calls directly in JSX — I still cringe thinking about early components where axios.get() was just sitting inside the render logic. Separate it. Always.

Not picking a naming convention — One component is userCard.jsx, the next is UserProfile.jsx, the next is user-settings.jsx. If you’re the only one on the project, it’s annoying. With a team, it becomes a real problem. Pick one style and stick with it from day one.

One Honest Thing Before You Go

There is no perfect folder structure. I know posts like this can make it sound like there’s one right answer — there isn’t.

The goal is consistency and clarity. Whatever structure you pick, the real test is: can someone new to the project figure out where things live without asking you? If the answer is yes, you’re doing fine.

Start simple. Refactor as you grow. Don’t let folder organization become something you spend more time thinking about than actually writing code.

And if you look back at an old project and cringe at how you organized it — that’s not a bad sign. That means you’ve learned something.