Update: Optimal file structure for React applications 1.1

Flattened asset directories 🥿

Originally, assets, such as images and SASS mixins, were put into an assets directory, e.g. assets/images/image-name.png. It offered no benefits to have an assets top-level directory and only served to cause confusion when attempting to categorize non-asset files, such as Redux reducers. For extensibility purposes, this directory has been flattened to just images, scss, reducers, or whatever category you need. Your directory structure is now simply src/CATEGORY/module-name.

Directory barrels 🎁

Directories that contain JavaScript imports are given “barrels,” or index.js files that re-export the contents of that directory. The most clear implementation of these are src/components and src/utils.

// src/components/index.js
export { default as App } from './app';
export { default as Breadcrumbs } from './breadcrumbs';
export { default as Button } from './button';
// src/utils/index.js
export { default as authenticateUser } from './authenticate-user';
export { default as isLoggedIn } from './is-logged-in';
export {
default as reduceLogGroupsToServiceNamespaces
} from './reduce-log-groups-to-service-namespaces';

Packages directory 📦

The packages directory is explicitly given a section to discuss a directory dedicated to modules that are re-usable outside of the current application. It is easiest to think of these as open source modules still in development. While they are not open source yet, they will be eventually, and they enforce a mindset that they should not be tightly coupled to the business logic of the application. If your company does not publish open source code, these modules may still be published internally for other teams (and external to the application itself).

Subcategory restructure 🥪

Subcategories (or categorized code that are uniquely dependencies of a parent module) are put into category directories and flattened to a max depth of 1. This makes more sense by example.

Previous directories:

PARENT MODULE: src/components/my-componentDEPENDENCIES:
src/components/my-component/icon/icon.js
src/components/my-component/icon/icon.scss
src/components/my-component/icon/index.js
src/components/my-component/icon/icon-svg/icon-svg.js
src/components/my-component/icon/icon-svg/icon-svg.scss
src/components/my-component/icon/icon-svg/index.js
src/components/my-component/use-some-hook/index.js
src/components/my-component/use-some-hook/use-some-hook.js

Current directories:

src/components/my-component/components/icon/icon.js
src/components/my-component/components/icon/icon.scss
src/components/my-component/components/icon/index.js
src/components/my-component/components/icon-svg/icon-svg.js
src/components/my-component/components/icon-svg/icon-svg.scss
src/components/my-component/components/icon-svg/index.js
src/components/my-component/components/index.js
src/components/my-component/hooks/index.js
src/components/my-component/hooks/use-some-hook/index.js
src/components/my-component/hooks/use-some-hook/use-some-hook.js

Hooks 🎣

The previous article did not do much besides mention hooks in passing. As shown in the subcategory restructure, we now explicit a place for hooks — in the hooks directory. This applies both to src/hooks and src/components/some-component/hooks. The ability to put hooks into barrels has done wonders for separately concerns during the test process. When I jest.mock(hooks, 'useSomeHook') to return { loading: true }, I expect my component to render a loading spinner. I do not have to setup, render, and teardown the entire application to render a loading spinner. I do not have to make or mock an API call to make sure that my loading spinner appears. Most importantly: I do not need to know the implementation details of my hook to make sure my component can accurately display a loading state. If my hook changes its API call, I should not have to update every test suite of every component that uses that hook. The barrel hooks directory is a miracle.

Conclusion 🔚

If you have any questions or great file structure input, please leave them in the comments below.

Senior front end engineer / charlesstover.com

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store