React Project Structure for Modularity and Reusability
Organize a React project into components, core, features, and shared directories with explicit dependency boundaries.
Directory Structure
- components
- Contains generic UI components such as elements, forms, layouts, and modals.
- These components can be used throughout the application and must not depend on a specific feature.
- core
- Holds application-wide infrastructure and configuration, including API clients, stores, models, and loaders.
- Can be referenced by
featuresandsharedbut must not referencefeatures.
- features
- Contains one module for each application feature.
- A feature may reference
components,core, andshared, but feature modules should not depend on one another directly.
- shared
- Contains reusable, non-visual utilities and logic shared by multiple features.
- Can be referenced by
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 separates UI primitives, application infrastructure, feature code, and reusable non-visual logic.
The separate components layer distinguishes application-wide UI primitives—such as buttons, layouts, and modals—from the non-visual utilities in shared.
As the project grows, placement is determined by responsibility rather than usage count: reusable UI belongs in components, reusable non-visual logic belongs in shared, and feature-specific code stays within its feature module.
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
Containerizing a FastAPI backend and deploying it to a single Lambda function with Lambda Web Adapter and AWS CDK.
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
Organize an Angular application into core, features, and shared directories with clear dependency boundaries.
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.
