10 Practical Ways to Organize and Scale Your React App

10 Practical Ways to Organize and Scale Your React App
May 18, 2025
6 min read

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!