Best Practices for Creating a Folder and File Structure for a React Application

wolfflucas

Lucas Wolff

Posted on June 21, 2023

Best Practices for Creating a Folder and File Structure for a React Application

When you start a new application one of the first decisions that you need to make is how to organize the folder structure.

It's common to spend a lot of time trying to create the perfect structure for new projects, but let me tell you: there's no such thing as the best folder structure.

Since every project has its own domain, goals and specifics, you need to reflect these singularities into your code, file and folder structure.

That's why it's so important to know and understand what you are going to create before actually starting creating it, and also because this structure plays a crucial role in the project's scalability and maintainability.

If you're not using an opinionated framework like Next.js, you'll be probably using Vite or even Create React App, so the chances are that you will need to create your own folder and file structure.

There are several different approaches to this, and today I'll show you what I usually use to start my projects and also the methodology and concepts behind it so you can create your own boilerplate.

Disclaimer

The organization that I'll be showing in this article is ideal for small to medium size projects. For big applications, there are better approaches like the feature-based architecture, screaming architecture and others, where you don't clutter your folders with unrelated files.

With that said, let's jump to the explanation!

Top-Level Folder Structure

In general your top-level folder structure will look like this:

dist/
public/
src/
...
Enter fullscreen mode Exit fullscreen mode

In this article I'll focus mainly on the src/ folder, which contains the files that you'll be working most of the time.

The src/ Folder

src/
|-- App.jsx
|-- index.css
|-- main.jsx
Enter fullscreen mode Exit fullscreen mode

The main.jsx is the entry point of the application, and basically renders the App.jsx into the DOM. This file also imports the index.css which is the top-level CSS file of the application, containing shared styles. If you're using TailwindCSS for example, this is the place where the @tailwind imports will be located.

The App.jsx file is the application itself. This is the place where you'll be adding the Router, Context Providers, setting up services and so on. Everything there is intended to be application-wide.

I propose the below file structure to start projects. Keep in mind that this can be used for projects of any size, but probably for huge ones you'll need to tweak some things.

src/
|-- adapters/
|-- assets/
|-- components/
|-- contexts/
|-- hooks/
|-- pages/
|-- services/
|-- utils/
Enter fullscreen mode Exit fullscreen mode

Now let's break down each folder to understand what they are supposed to do.

src/adapters

Here you'll have adapters to external sources e.g., APIs, browser features like Local Storage, and File System. This folder can be also called providers/ but this may be confusing due to the Context API providers. Or even lib/, but I do prefer to call it adapters/.

Example:

src/
|-- adapters/
|---- api.js
|---- localStorage.js
...
Enter fullscreen mode Exit fullscreen mode
// src/adapters/api.js
export const api = {
  get: (url) => axios.get(url),
  // ...
};

// src/adapters/localStorage.js
export const localStorage = {
  get: (key) => {
    const value = localStorage.getItem(key);
    if (value) {
      return value;
    }

    throw new Error("KEY_NOT_FOUND");
  },
  // ...
};
Enter fullscreen mode Exit fullscreen mode

src/assets

This folder is intended to serve static assets like images, SVGs, and videos. Feel free to create as many folders as you need, always focusing on the organization of the folder structure.

Example:

src/
|-- assets/
|---- image/
|------ logo-transparent.png
|------ clients/
|-------- foo-logo.png
|-------- bar-profile-picture.png
|---- svg/
|------ loading-spinner.svg
...
Enter fullscreen mode Exit fullscreen mode

src/components

Here is the place where all your components will live—except the main pages.

There are several ways to divide this folder internally depending on the project needs. I like to create folders to group related components, and then component folders inside them.

src/
|-- components/
|---- core/
|---- forms/
|---- layouts/
|---- pages/
|---- shared/
...
Enter fullscreen mode Exit fullscreen mode

Understanding the structure:

  • core/: isolated components that are the building-blocks of the application;
  • forms/: components used to build forms;
  • layouts/: the layouts of the application, used on each page;
  • pages/: components used inside specific pages;
  • shared/: components that can be shared between more than one page.

Example:

src/
|-- components/
|---- core/
|------ Card/
|-------- Card.jsx
|-------- Card.test.js
|-------- style.scss
|-------- index.js
|---- forms/
|------ TextInput/
|-------- TextInput.jsx
|-------- TextInput.test.js
|-------- style.scss
|-------- index.js
|---- layouts/
|------ PageLayout/
|-------- PageLayout.jsx
|-------- PageLayout.test.js
|-------- style.scss
|-------- index.js
|---- pages/
|------ HomePage/
|-------- HomeCarousel/
|---------- HomeCarousel.jsx
|---------- HomeCarousel.test.js
|---------- style.scss
|---------- index.js
|---- shared/
|------ ShoppingCart/
|-------- ShoppingCart.jsx
|-------- ShoppingCart.test.js
|-------- style.scss
|-------- index.js
...
Enter fullscreen mode Exit fullscreen mode

src/contexts

This folder will contain all the state management's contexts that your application will use. This may vary if the application uses other solutions like Redux. In this case—if you follow the Redux Toolkit patterns—you'll need to create a features folder, or slices.

The general idea here is not the name of this folder, but its purpose.

Since this folder is heavily dependent on the state management solution that is being used, you'll need to adapt it to the needs of the chosen tool.

src/hooks

The place where all the application's hooks will be located. Hooks can also be understood as the features of your application, which you can hook into as many components as you need.

Based on that, you can also create inner folders related to each feature to make the structure more readable and encapsulated.

Example:

src/
|-- hooks/
|---- useForm.js
|---- useWindowSize.js
|---- authentication/
|------ useLogin.js
|------ useSignUp.js
...
Enter fullscreen mode Exit fullscreen mode

Here the useForm and useWindowSize are both global level hooks. The ones under the authentication/ folder are strictly related to the authentication feature of the application.

src/pages

This folder contains all the pages of your application. The idea of each page is to use the components from the components folder to build the UI.

The pages can use components from all the folders, but will use mainly from these:

  1. src/components/layouts/: to build the base layout of the page;
  2. src/components/pages/PAGE_NAME: to get specific components for the related page;
  3. src/components/core/: to use elements like Button and Typography to build the page;
  4. src/components/shared/: to use elements that are shared between pages;

I didn't add the forms component because it's ideal that each form has its own component inside the shared/ or pages/ folder. But feel free to get the form components directly if needed.

src/services

All the calls for each API endpoint will be under this folder. Each service will probably use the API adapter to call the API, and will be called inside a hook, which is called inside the components. I wrote an article around this topic, explaining how to organize your API calls correctly.

You can also create top-level files for each group of services or one service per file, or even create folders for each type of service, it's up to you.

The mentioned approaches are exemplified below:

TOP-LEVEL FILE:
src/
|-- services/
|---- user.js (exports functions like getUser, createUser, etc.)

OR

ONE SERVICE PER FILE:
src/
|-- services/
|---- getUser.js
|---- createUser.js

OR

GROUP SERVICES BY TYPE:
src/
|-- services/
|---- user/
|------ getUser.js
|------ createUser.js
|------ index.js (exports all functions)
Enter fullscreen mode Exit fullscreen mode

Again, the best approach is the one that fits your needs and the needs of your team.

src/utils

Utils are pure JavaScript functions that can be reused across the application. Pure functions are basically functions that, given an input, will always return the same value.

The same idea used above for the services can be used for the utils:

TOP-LEVEL FILE:
src/
|-- utils/
|---- user.js (exports functions like calculateUserGrades, isUserBirthday, etc.)

OR

ONE UTIL PER FILE:
src/
|-- utils/
|---- calculateUserGrades.js
|---- isUserBirthday.js

OR

GROUP UTILS BY TYPE:
src/
|-- utils/
|---- user/
|------ calculateUserGrades.js
|------ isUserBirthday.js
|------ index.js (exports all functions)
Enter fullscreen mode Exit fullscreen mode

File Naming Conventions

In the examples all the file names are very simple, following the pattern of [filePurpose].[fileExtension], like [createUser].[js].

Although one very common patter is to put the type of the file in the name before the extension. This is a matter of choice, and for some people it can improve the readability of the project. For example:

  • services/createUser.jsservices/createUser.service.js
  • utils/isUserBirthday.jsutils/isUserBirthday.util.js

Also, for the React components I always use Pascal Case (ComponentName), and I like to use camel-case (fileName) instead of kebab-case (file-name) for file names that are not React components, like services and utils.

But for folders, I prefer to use the kebab case if they have multiple words. One example is a service folder for a resource that deals with product categories. I'd create a group folder like:

src/
|-- services/
|---- product-categories/
|------ getProductCategories.js
|------ updateProductCategory.js
Enter fullscreen mode Exit fullscreen mode

Conclusion

Project structure is a very important and also personal topic. Using frameworks like Next.js makes things easier in this sense because they are very opinionated.

One idea is to create a project using Next.js and then clone it using Vite, for example, so you can compare and create your own boilerplate.

My goal here was to give you some direction towards your own project structure. You can use this idea as a boilerplate but always remember to follow the structure that fits best your needs.


If you have any feedback or suggestions, send me an email

Great coding!

💖 💪 🙅 🚩
wolfflucas
Lucas Wolff

Posted on June 21, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related