React Project Structure for Modularity and Reusability
Splitting a React project into components, core, features, and shared directories, each with a defined dependency direction.
Directory Structure
- components
- Contains simple and abstract common components.
- These components are used across the project and can be considered application-wide parts.
- core
- Holds the application-core functionality with application-wide utilities.
- Accessible from
featuresandsharedbut must not referencefeatures.
- features
- Each feature module resides here.
- These modules may reference
components,coreorsharedbut must remain isolated from the rest of the application to maintain modularity.
- shared
- Contains shared utilities and components.
- Accessible from
featuresbut must not reference them.

src/├── assets/├── components/│ ├── Elements/│ ├── Forms/│ ├── Layouts/│ ├── Modals/│ ├── Pages/│ │ ├── Errors/│ │ │ ├── AccessDeniedPage.tsx│ │ │ ├── NotAuthenticatedPage.tsx│ │ │ ├── SystemErrorPage.tsx│ │ │ ├── ...│ │ ├── ErrorBoundary.tsx├── core/│ ├── api/│ │ ├── interceptors/│ ├── config/│ ├── hooks/│ ├── loaders/│ ├── models/│ │ ├── api/│ ├── stores/│ ├── utils/├── features/│ ├── auth/│ ├── .../├── shared/Conclusion
Splitting a React project into components, core, features, and shared directories, each with a defined dependency direction, keeps UI primitives, application-wide logic, and feature code from bleeding into each other. The extra components layer is what distinguishes this structure from a typical core/features/shared split: it separates application-wide UI primitives (buttons, layouts, modals) from shared, which is meant for reusable non-visual utilities and logic. That distinction matters in practice — as the project grows, it keeps a question like “should this button variant go in components or shared” from becoming ambiguous, since the answer is always determined by whether it’s a UI element or not, rather than by how many features happen to use it.
Related posts
Sign in with Slack Using Cognito User Pools and OIDC
Federating Cognito user pools with Slack over OIDC and wiring "Sign in with Slack" into a Next.js app with Amplify.
Deploying FastAPI on AWS Lambda with Lambda Web Adapter
This example guides you through the process of developing API backends with FastAPI using Lambda Web Adapter.
Testing ECMAScript Modules with Jest
Fixing Jest's "Cannot use import statement outside a module" error by wiring up ESM support across package.json, TypeScript, and Jest config.
Angular Project Structure for Modularity and Reusability
This note outlines an Angular folder structure with core, features, and shared modules to keep the app modular and reusable.
Spying on Mock Object Properties in Jasmine
Working around Jasmine's "already been spied upon" error when spying on a mocked object's property with Object.getOwnPropertyDescriptor.
