10 Practical Ways to Organize and Scale Your React App

1. Organize by Domain, Not Technical Role
Avoid sorting components strictly by type (e.g., presenters, containers). Instead, group by domain or feature.
Avoid this:
/src
components/
Header.js
Footer.js
containers/
InvoicesContainer.js
PaymentProfilesContainer.js
presenters/
InvoicesPresenter.js
PaymentProfilesPresenter.js
Prefer this:
/src
pages/
billing/
invoices/
index.ts
payment-profiles/
index.ts
login/
index.ts
2. Place Components in Folders
For complex components, use folders to encapsulate logic, styles, and tests.
Avoid this:
components/
Accordion.ts
Alert.ts
Prefer this:
components/
accordion/
index.ts
alert/
Alert.tsx
AlertTitle.tsx
Alert.test.tsx
Alert.stories.tsx
index.ts
3. Favor Absolute Imports
Relative paths get messy fast. Use absolute imports for better readability and refactoring.
Avoid:
import { formatDate } from '../../../utils';
Prefer:
import { formatDate } from '@common/utils';
4. Use a Common Module
Centralize shared utilities, hooks, and components to avoid duplication.
Structure Example:
/src
common/
components/
dialogs/
index.ts
forms/
index.ts
hooks/
useDialog.ts
useForm.ts
utils/
formatDate.ts
5. Abstract External Libraries
Avoid sprinkling 3rd party libraries throughout your app. Wrap them instead.
Avoid:
import { Button } from 'react-bootstrap';
Prefer:
import { Button } from '@components/ui';
6. Manage Cross-Module Dependencies
Move shared logic or components used across multiple pages into the common module. This avoids duplication and clearly defines dependencies.
7. Keep Logic Close to Where It’s Used (LoB Principle)
Place related code (e.g., hooks or utils) inside the same folder as the feature/page that uses it.
Structure Example:
pages/
billing/
invoices/
index.tsx
hooks/
useInvoices.ts
utils/
formatAmount.ts
8. Be Cautious with Utility Functions
Keep utility functions pure and domain-agnostic. Business logic should be separated.
Avoid:
// utils/processInvoice.ts export function processInvoice(data) { if (data.status === 'paid') ... }
Prefer:
// utils/format.ts export function formatAmount(amount) { ... } // business/invoiceLogic.ts export function processInvoice(data) { ... }
9. Separate Business Logic From UI
UI components should focus on rendering. Use custom hooks to extract logic.
Avoid:
function InvoiceList() { useEffect(() => { fetch('/api/invoices') }, []); return <div>...</div>; }
Prefer:
function useInvoices() { // business logic } function InvoiceList() { const { invoices } = useInvoices(); return <div>{invoices.map(...)}</div>; }
10. Pin Your Dependencies
Don’t rely on version ranges. Always pin specific versions in package.json
to avoid unexpected behavior.
Avoid:
"react": ">=16.8.0", "express": "^4.17.1"
Prefer:
"react": "16.8.0", "express": "4.17.1"
Conclusion
Scalable apps don’t happen by accident. Apply these principles consistently, and your codebase will be easier to grow, test, and maintain. Think of your React project like a building — invest in a strong foundation.
Happy coding!