Photo by Desola Lanre-Ologun on Unsplash
How to Structure React Projects From Beginner To Advanced in 2023
Table of contents
Structuring large React applications into folders and files can be a challenging task as there is no definitive approach given by React itself. However, as someone who has been implementing React applications for years, I worked with different structures in my one-man projects, in the fast-paced environment of small startups, and in international projects (with multiple cross-functional teams).
Without a proper strategy in place, working on a React project can become a daily chore, costs million (sadly happened to one of my clients) to refactor and restructure, and is an overwhelming task.
In this guide, I will share with you the 3 levels I see companies structure their React projects. You can decide what works for you and how much you want to customize it. While the co-author of Redux and the Create React App may simply move files around until it feels right without a clear vision, this may not be suitable for larger cross-functional teams. Therefore, this guide serves as a reference for those seeking clarity on this subject.
Stages of a Project
It's essential to understand that there is no one-size-fits-all solution when it comes to React projects. Each project is unique and requires its own strategy since various ways exist to approach the same problem. To create a successful React project, it's crucial to consider the project's specific context and determine the most suitable solution. This process may involve experimenting with different options and approaches until the best one is identified.
When it comes to file organization, the most effective approach varies depending on personal preferences, project size, technology used, and team habits. Establishing a set of file conventions (more like guidelines) can be useful for any project, big or small, to ensure everyone is on the same page with file organization.
By the way, a wonderful way to document conventions is the usage of Architectural Decision Records (ADRs). To give you an example of a structure ADR you can look at this ADR from the core team of Spotify π
π₯Beginner Structure for Small Projects
Great approach for projects with 10-20 components, like a single portfolio page or a smaller landing page.
If you're just starting with React.js and working on a project with less than 20 components, it's essential to organize your files in a simple and straightforward manner. You probably use a tool like Create React App and get a project structure generated.
A good practice is to create a components/
and hooks/
folder under the src/
folder.
Structure
my-app/
ββ README.md
ββ ...
ββ src/
β ββ components/
β β ββ Button.js
β β ββ Button.css
β β ββ Button.test.js
β β ββ Home.js
β β ββ Home.css
β β ββ Home.test.js
β ββ hooks/
β β ββ useApi.js
β β ββ ...
β ββ App.js
β ββ index.css
β ββ ...
ββ ...
components/
The components/
folder in the beginner structure is very easy to understand since it contains every component in your application. However, as your project grows beyond 20 components, this folder can become disorganized and challenging to manage. That's why in more complex folder structures, components are distributed across multiple folders and organized in a structured way. But for small projects, this extra level of complexity is unnecessary, and a single components/
folder is sufficient.
hooks/
The hooks/
folder is where you'll find all the custom hooks used in your project. This folder is helpful in any project size, as custom hooks are typically used in many places throughout the codebase. Having a centralized location for all the custom hooks can make it easier to find and manage them.
π Advantages
The most significant advantage of this folder structure is its simplicity. It's straightforward and easy to understand, making it an excellent choice for small projects.
π Disadvantages
One major drawback of this folder structure is that it doesn't provide guidance on how to handle files such as images, utility functions, or React contexts. This is because smaller projects generally don't have many of these types of files, so storing them in the root of the src folder is sufficient. However, as the project grows, it can quickly become disorganized and difficult to manage. That's why, for any project beyond a small size, it's recommended to use at least an intermediate folder structure to keep everything organized and easy to find.
Summary
When starting with React.js and working on a project with fewer than 20 components, it's crucial to organize your files in a simple and straightforward manner. This can make it easier to understand and navigate your codebase, and help you avoid potential issues with maintenance and scalability.
However, as your project grows in size and complexity, you may need to consider the usage of the intermediate organizational structures.
π₯Intermediate Folder Structure for Small Startups
Great for projects that will be large and need multiple developers working on them. Each important part of your project has its own folder and improves the simultaneous work on the app. Pages are now separated.
The most notable change from the simple folder structure is that we're now dividing our project into pages and more subcomponents, where each page holds all the logic related to a specific page in a single file, instead of having to search through multiple folders and unrelated files. In addition, you start creating more and more reusable components.
This approach is especially beneficial for the beginning of larger projects.
Structure
my-app/
ββ README.md
ββ ...
ββ src/
β ββ assets/
β ββ components/
β β ββ Form/ // ui folder for form elements according to your design system
β β β ββ Button.js
β β β ββ Button.css
β β β ββ Button.test.js
β β β ββ ...
β β ββ Map/ // custom component for integration of Maps Provider, like Google Maps
β β β ββ ...
β β ββ LoginForm/ // module that is used for the login page
β β β ββ index.js
β β β ββ LoginForm.js
β β β ββ useLogin.js
β β β ββ ...
β ββ context/ // Sometimes called store, redux or similar
β ββ data/
β ββ hooks/
β ββ layouts/
β ββ pages/
β β β ββ Home/
β β β β ββ index.js
β β β ββ Login/
β β β β ββ index.js
β β β ββ SignUp/
β β β ββ ...
β ββ services/ // sometimes called apis
β ββ utils/
β ββ App.js
β ββ index.js
β ββ ...
ββ ...
As you can see above, this folder structure contains a significant number of folders that encompass almost every possible file type you might need in a React project. With this structure, it's best to avoid having any files in the root of the src folder, except for files like index.js.
assets/
In the assets/
folder, you can find all non-code-related files such as images, global CSS files, font files, and more, which are essential components of your project. This folder serves as a central location for storing all such files.
components/
The components/
folder in this example is structured into subfolders, which is a significant change. This approach is useful in keeping your components organized into distinct sections, instead of being lumped together as a single mass. For instance, the Form/
folder houses all the form-specific components such as buttons, checkboxes, selects, β¦, while the Map/
folder contains customized components of external libraries, like Google Maps.
Also, bigger features of an application are stored here as a folder, like LoginForm/
with its own custom hooks and components. Components of the LoginForm/
can then import more general components from the other folders, like the Button from Form/
.
You can customize and organize the components/
folder as per your project needs, but it's best to avoid it from getting too large. Too many folders lead often to code smells, like code duplication because other teams are simply not aware that this component exists elsewhere already. Good advice is to not get your folders larger than 8 items for every level of your structure. Otherwise, you make it hard for people to remember what they first read.
context/
The context/
folder is for all the React context files that are utilized across multiple pages in your project. In larger projects, you'll likely have several contexts that you'll use throughout your application, making this folder an invaluable asset. However, if you're using a distinct global data store, like Redux, you may want to substitute this folder with a more relevant set of folders specifically designed to store your Redux files.
data/
The data/
folder is designated for storing data assets like JSON files that contain information that's utilized in your code, like store items or theme information. In addition, this folder can also store a file that contains global constant variables. This is beneficial when you have a multitude of constants that you use across your application, like environment variables.
hooks/
The hooks/
folder remains unchanged from the simple folder structure. However, in this advanced structure, it will only store the global hooks that are utilized across multiple pages, as opposed to storing every hook globally in your application. Some of the hooks will be moved to the specific components in your components folder.
layout/
The layout/
folder is used to define the layout structure of the pages in the application.
Layouts are the skeleton of a page, and they contain the common elements that are shared across multiple pages, such as headers, footers, navigation menus, and so on. By defining a default layout for a page, you can avoid repeating the same code across all pages and ensure consistency across the application.
pages/
The main change in this folder structure is the inclusion of the pages/
folder, which should have a folder for each page in your application. Within each page folder, there should be a single root file (usually index.js).
This separation of page-specific code from more general global code is the primary advantage of this system compared to the simple folder structure. It's easier to understand the core functionality of your application when pages are separated.
services/
The services/
folder is a common convention for organizing files related to interacting with external APIs or services.
Services are typically used to abstract away the details of interacting with external APIs or services from the rest of the application's code, making it easier to maintain and test. In the services/
folder, you might find code that handles tasks such as authentication, data fetching, and data transformation.
utils/
The last addition to the folder structure is the utils/
folder, which is designated for storing all utility functions, such as formatters. The folder is quite straightforward, and all the files contained within should be as well. If you do use a utils/
folder, it's a good practice to organize the code into smaller, more specific subfolders, such as stringUtils
, mathUtils
, or dateUtils
, to make it easier to find and understand the code. It's also important to regularly review and clean up the utils/
folder to remove any unnecessary or duplicated code.
π Advantages
The primary benefit of this new system is that each part of the project has its own folder, which ensures that the root src/
folder has very few files in it. Another significant advantage is that pages are now showing the main functionalities of your page and you start to reuse your components.
As a project expands, it becomes more and more critical to store files used together in the same location, as it simplifies code comprehension, writing, and reading by reducing the amount of global code kept in your general components, hooks, and other folders.
π Disadvantages
The major drawback of this system is that, as your application grows even larger, the components/
folder will become bloated and hard to expand. This is due to the fact that, as your application expands to include more pages, a single feature is often used across multiple pages instead of just one. In such cases, you must relocate the code to other folders in your app, and refactor the feature component to be usable on multiple pages, which starts getting messy. Typical larger projects might have hundreds of custom components.
As your project grows, almost all of your code will be shared across multiple pages, necessitating the use of an advanced folder structure.
Summary
For most medium-sized projects, this is a great start to grow from, like MVPs. You create more and more pages and develop more and more components.
When your projects start to mature into a large app with multiple teams working on it, you may need to consider the usage of the advanced folder structure.
π₯Advanced Folder Structure for Larger Projects
For enterprise-scale products with multiple departments and cross-functional teams. The
packages/
andmodules/
folders are a convention that some React projects use for organizing code into reusable packages or libraries, making the codebase more modular, maintainable, and shareable.packages/
andmodules/
enable the simultaneous work of many departments. At the same time, complexity rises for deployment, versioning, developer onboarding, and overall management.
Upon a quick glance at the intermediate and large project structures, you may observe numerous similarities. However, there is a notable distinction, which is the replacement of the components/
with packages/
folder and adding of the modules/
folder.
The modules/
folder provides a more refined approach to organizing similar code and, unlike the components/
folder in the intermediate folder structure does not encounter issues with extensive overlap between modules, as it is unlikely that your module will have significant amounts of overlap.
Given that many of the folders in this structure are replicated from the intermediate structure, I will solely focus on the folders that have undergone changes in these two structures.
Structure
my-app/
ββ README.md
ββ ...
ββ src/
β ββ assets/
β ββ packages/ // earlier components/ folder. Sometimes called lib
β β ββ UI/
β β β ββ components/
β β β β ββ Form/
β β β β β ββ Button.js
β β β β β ββ Button.css
β β β β β ββ Button.test.js
β β β β β ββ ...
β β β β ββ DataDisplay/
β β β β β ββ Card.js
β β β β β ββ ...
β β β ββ services/
β β β ββ hooks/
β β β ββ context/
β β β ββ package.json
β β β ββ ...
β β ββ Map/ // external library customized and imported as a package
β β ββ ...
β ββ context/
β ββ data/
β ββ modules/ // sometimes called plugins or features
β β ββ LoginForm/
β β β ββ index.js
β β β ββ components
β β β β ββ LoginForm.js
β β β ββ hooks/
β β β β ββ useLogin.js
β β β β β ββ ...
β β β ββ context/
β β β ββ services/
β β β ββ ...
β β β ββ package.json
β β ββ ...
β ββ hooks/
β ββ layouts/
β ββ pages/
β β β ββ Home/
β β β β ββ index.js
β β β ββ Login/
β β β β ββ index.js
β β β ββ SignUp/
β β β ββ ...
β ββ services/
β ββ utils/
β ββ App.js
β ββ index.js
β ββ ...
ββ ...
packages/
The packages/
folder are not a standard part of a React project, but rather a convention that some projects use for organizing code into reusable packages or libraries.
Packages are essentially independent modules of code that can be imported and used in other parts of the application. By organizing code into packages, you can create a more modular and reusable codebase, making it easier to maintain and update the application over time.
In a packages/
folder, you might find multiple subfolders, each containing its own source code, documentation, hooks, services, tests, and other related files.
Using packages in this way can also make it easier to share code across multiple projects or teams. If you have a set of utilities or components that are commonly used across different projects, you can package them up and share them via a private or public package registry, such as npm.
modules/
Using modules/
folder is a way to organize related code and functionality within the application. Each module might represent a distinct feature or component of the application, such as user authentication, search functionality, or a shopping cart.
Modules can contain multiple files, such as components, hooks, utility functions, styles, and tests, all related to the same feature or component. By organizing code into modules, you can create a more modular and maintainable codebase, making it easier to reason about and update the application over time.
Using modules can also make it easier to share code across different parts of the application or with other developers. If you have a module that is used in multiple places throughout the application, you can simply import it where needed, rather than duplicating the code in multiple places.
services/
In my personal experience in this stage, most of the services are now part of either a package or a module. May differ for your project.
utils/
Having a utils/
folder in a React project is not an inherently bad practice, as it can be a useful way to organize small, reusable functions and utilities that are used across the project.
However, in a large-scale React project, the utils/
folder can become a dumping ground for unrelated or poorly organized code, which can lead to issues with maintainability, readability, and code bloat.
π Advantages
By using a packages/
and modules/
folder, you can separate related code into smaller chunks, making it easier to find and update specific parts of the application.
When code is organized intopackages/
and modules/
, components and logic can be more easily reused throughout the application. For example, you may have a module that handles user authentication, which can be used in multiple places throughout the application.
When multiple developers are working on a large-scale project, it can be challenging to maintain code consistency and avoid conflicts. By using packages and modules, you can make it easier for developers to work independently on different parts of the codebase without interfering with one another.
As your project grows and evolves over time, it can be challenging to maintain a well-organized codebase. By using packages and modules, you can ensure that your code remains manageable and scalable over time.
Breaking down the application into smaller, more modular pieces can make it easier to organize and maintain the codebase over time for multiple teams in a larger organization.
π Disadvantages
Organizing code into smaller packages and modules can add a layer of complexity to the project, which can make it harder to understand and navigate, especially for new team members.
Breaking more specific packages and modules down can be over-engineering, especially for smaller projects. This can lead to unnecessary code bloat and complexity.
As the project grows and changes over time, it can be challenging to maintain the organization and structure of the codebase, which can result in confusion and mistakes.
Without proper management, it can be easy to create duplicate or overlapping functionality across multiple packages or modules, which can lead to maintenance issues and bugs.
Summary
Overall, the decision to use packages/
and modules/
folders in a large-scale project should be based on the specific needs of the project and team. While the advanced structure can offer benefits, especially for multiple cross-functional teams, it's important to carefully consider the potential downsides and ensure that the project's codebase remains manageable and maintainable over time.
Conclusion
Overall, the decision to use a beginner, intermediate, or advanced structure for your project should be based on the specific needs of the project and team. You can customize those folders at any part to whatever fits best for you.
Ultimately, the key is to find an organizational structure that works best for your project and team.
Bonus Material
Some great things to consider when organizing your react project:
Atomic Design by Brad Frost
Monorepos and tools, like Turborepo
Thanks for reading. Hope this gives you some insights into how many corporates structure their project and their potential pitfalls.
What do you think of this structure?
Do you use a different structure?
If you want to meet and talk about it feel free.
All the best,
Deni