Folder Structure in React Apps
And How to Make Them Scale
React is one of the most popular JavaScript frameworks currently being used. With over two million weekly downloads of React from npm, there’s no doubt that there are tons of React applications out there. With some major companies using React (Facebook, Airbnb, American Express, AMC Theatres, and many more), these applications must be massive and must somehow be structured in a way that’s easy to manage and easy to scale. So how do they do it?
If you’ve been developing in React for awhile, especially if you’ve added a state management framework like Redux, you know that there can end up being tons of folders and files in your application. When you need to scale these applications to handle a larger code base, it can seem almost like an impossible task. Both React and Redux offer some solutions for folder structure of your application, but neither of them really give you a clear “this is how you do it” answer.
So let’s take a deeper look at the suggestions that React and Redux give us for structuring our applications. Then it’s up to you to determine which solution will work best for your project.
React’s Recommendations
If you navigate to the File Structure section of React’s website, the very first sentence states:
React doesn’t have opinions on how you put files into folders.
Not very helpful if you look at it skin deep. However, what this sentence is really saying is not that the creators of React don’t care where you put your files, but that the language itself doesn’t care. React will “react” the same way to your application’s changes no matter if your application exists entirely in one index.js
file or if every bit is broken out into separate folders and files. It is up to you to decide how you want to structure things.
Now, even though they state that React doesn’t have an opinion, they do offer some patterns that you can follow until you feel that they’re no longer applicable for your needs.
Grouping By Feature or Route
The first suggested folder pattern is grouping by features or by routes. For example, if I have an application with a home page and an about page, I might have two folders, home/
and about/
that contain the components, tests, and styles for those routes. Now, let’s say that my home page has a feed feature that I might want to reuse in a different part of my application (such as a blog portion). I might choose to have a section outside of the home/
folder called feed/
. This can be a way to organize your application by function and to easily be able to find which part of the application you’re looking for.
Grouping by File Type
The second suggestion is grouping your application by file type. Grouping files by file type can be helpful when navigating your applications. If you’re looking for the Avatar component, it’s going to be under the components folder. However, if you have over 50 components, that folder is going to be large. A way to manage the abundance of files, is to nest the components into categorical folders based on the components’ role in the application. This practice could be based off of something like Brad Frost’s Atomic Design.
Atomic Design breaks up user interfaces into five categories: Atoms, Molecules, Organisms, Templates, and Pages. When following this pattern, smaller components, or Atoms, can be combined to make Molecules. Molecules can be combined to make Organisms, and so on and so forth. This allows us to truly modularize and componentize every aspect of our applications for easier reuse.
Be careful when using this approach: you don’t want to nest your components too deeply. Deeply nested directories in JavaScript can cause many pain points, such as difficulty writing relative imports and updating those imports. React recommends limiting yourself to a maximum of three to four nested folders deep within a single application.
Redux’s Recommendations
When you add in state management, like Redux, you add more files, folders, and complexity to the architecture of your application. Especially if you accidentally end up following this Redux anti-pattern by creating an action and reducer for each corresponding view. So how do we avoid this anti-pattern and structure our Redux actions and reducers in a way that’s scalable? Here’s what Redux recommends.
Rails-Style
Redux’s first recommendation is that your architect your applications similar to how Ruby on Rail’s applications are structured: with a separate folder for actions, constants, reducers, containers, and components. Similar to the grouping by file type approach, your application would be structured by the purpose that each file serves in your application. You could also use Brad Frost’s Atomic Design principles to break subfolders down in a similar fashion.
Ducks
Redux Ducks is a system that was proposed by Erik Rasmussen (github, medium) and has gained popularity as being a viable solution to scaling Redux applications. Ducks proposes that instead of keeping actions, action types, and reducers in their own separate files per components, these necessities of Redux should be modularized in a way that they can be self contained. This alleviates the pain of having an actions.js
, actionTypes.js
, and reducer.js
file within each component’s domain.
So What’s the Right Solution?
There is no right solution.
Every application is different in some way or another and each project has its own different needs. How we structure our applications should change based on the needs of the project, just like the technologies we choose.
What works for you in one application may fall apart completely in another. These suggestions from React and Redux are meant to be guidelines to get you going in the right direction. Your solution might be a mix of all the proposed architecture solutions.
Personally, I like to structure my applications by separating my stateful containers from my stateless components. This way, when my application components start to get too large, I can take components that are used in multiple places and modularize them in an component library. This allows my application to consume these components without making my current folder tree to large.
In addition, my containers and components are grouped by route. For example, in my containers/
folder, I will have a subfolder called home/
for all of the containers that live on the home page. The same is true for my components/
folder.
Don’t Overthink It
Pick a folder structure that works for your application. If you’re spending a massive amount of time organizing and reorganizing components, containers, styles, reducers, sagas (if you’re using redux-saga, which you should), you’re doing it wrong.
Even Dan the Man gave us this solution:
And when you click that link, it takes you to a seemingly boring page that looks like this:
That’s exactly what you should do. You should move things around until they feel right. If your application is a pain to find things in or if your imports look whack, you know that the current architecture you’re using probably isn’t the best one you could be using. So play around with it until it feels right.
📝 Read this story later in Journal.
🗞 Wake up every Sunday morning to the week’s most noteworthy Tech stories, opinions, and news waiting in your inbox: Get the noteworthy newsletter >