File Organization
Proper file and directory structure for maintainable, scalable frontend code in the the application.
Overview
File Organization
Proper file and directory structure for maintainable, scalable frontend code in the the application.
features/ vs components/ Distinction
features/ Directory
Purpose: Domain-specific features with their own logic, API, and components
When to use:
- Feature has multiple related components
- Feature has its own API endpoints
- Feature has domain-specific logic
- Feature has custom hooks/utilities
Examples:
features/posts/- Project catalog/post managementfeatures/blogs/- Blog builder and renderingfeatures/auth/- Authentication flows
Structure:
features/
my-feature/
api/
myFeatureApi.ts # API service layer
components/
MyFeatureMain.tsx # Main component
SubComponents/ # Related components
hooks/
useMyFeature.ts # Custom hooks
useSuspenseMyFeature.ts # Suspense hooks
helpers/
myFeatureHelpers.ts # Utility functions
types/
index.ts # TypeScript types
index.ts # Public exports
components/ Directory
Purpose: Truly reusable components used across multiple features
When to use:
- Component is used in 3+ places
- Component is generic (no feature-specific logic)
- Component is a UI primitive or pattern
Examples:
components/SuspenseLoader/- Loading wrappercomponents/CustomAppBar/- Application headercomponents/ErrorBoundary/- Error handlingcomponents/LoadingOverlay/- Loading overlay
Structure:
components/
SuspenseLoader/
SuspenseLoader.tsx
SuspenseLoader.test.tsx
CustomAppBar/
CustomAppBar.tsx
CustomAppBar.test.tsx
Feature Directory Structure (Detailed)
Complete Feature Example
Based on features/posts/ structure:
features/
posts/
api/
postApi.ts # API service layer (GET, POST, PUT, DELETE)
components/
PostTable.tsx # Main container component
grids/
PostDataGrid/
PostDataGrid.tsx
drawers/
ProjectPostDrawer/
ProjectPostDrawer.tsx
cells/
editors/
TextEditCell.tsx
renderers/
DateCell.tsx
toolbar/
CustomToolbar.tsx
hooks/
usePostQueries.ts # Regular queries
useSuspensePost.ts # Suspense queries
usePostMutations.ts # Mutations
useGridLayout.ts # Feature-specific hooks
helpers/
postHelpers.ts # Utility functions
validation.ts # Validation logic
types/
index.ts # TypeScript types/interfaces
queries/
postQueries.ts # Query key factories (optional)
context/
PostContext.tsx # React context (if needed)
index.ts # Public API exports
Subdirectory Guidelines
api/ Directory
Purpose: Centralized API calls for the feature
Files:
{feature}Api.ts- Main API service
Pattern:
// features/my-feature/api/myFeatureApi.ts
getItem: async (id: number) => {
const { data } = await apiClient.get(`/blog/items/${id}`);
return data;
},
createItem: async (payload) => {
const { data } = await apiClient.post('/blog/items', payload);
return data;
},
};
components/ Directory
Purpose: Feature-specific components
Organization:
- Flat structure if <5 components
- Subdirectories by responsibility if >5 components
Examples:
components/
MyFeatureMain.tsx # Main component
MyFeatureHeader.tsx # Supporting components
MyFeatureFooter.tsx
# OR with subdirectories:
containers/
MyFeatureContainer.tsx
presentational/
MyFeatureDisplay.tsx
blogs/
MyFeatureBlog.tsx
hooks/ Directory
Purpose: Custom hooks for the feature
Naming:
useprefix (camelCase)- Descriptive of what they do
Examples:
hooks/
useMyFeature.ts # Main hook
useSuspenseMyFeature.ts # Suspense version
useMyFeatureMutations.ts # Mutations
useMyFeatureFilters.ts # Filters/search
helpers/ Directory
Purpose: Utility functions specific to the feature
Examples:
helpers/
myFeatureHelpers.ts # General utilities
validation.ts # Validation logic
transblogers.ts # Data transblogations
constants.ts # Constants
types/ Directory
Purpose: TypeScript types and interfaces
Files:
types/
index.ts # Main types, exported
internal.ts # Internal types (not exported)
Import Aliases (Vite Configuration)
Available Aliases
From vite.config.ts lines 180-185:
| Alias | Resolves To | Use For |
|---|---|---|
@/ | src/ | Absolute imports from src root |
~types | src/types | Shared TypeScript types |
~components | src/components | Reusable components |
~features | src/features | Feature imports |
Usage Examples
// ✅ PREFERRED - Use aliases for absolute imports
// ❌ AVOID - Relative paths from deep nesting
When to Use Which Alias
@/ (General):
- Lib utilities:
@/lib/apiClient - Hooks:
@/hooks/useAuth - Config:
@/config/theme - Shared services:
@/services/authService
~types (Type Imports):
~components (Reusable Components):
~features (Feature Imports):
File Naming Conventions
Components
Pattern: PascalCase with .tsx extension
MyComponent.tsx
PostDataGrid.tsx
CustomAppBar.tsx
Avoid:
- camelCase:
myComponent.tsx❌ - kebab-case:
my-component.tsx❌ - All caps:
MYCOMPONENT.tsx❌
Hooks
Pattern: camelCase with use prefix, .ts extension
useMyFeature.ts
useSuspensePost.ts
useAuth.ts
useGridLayout.ts
API Services
Pattern: camelCase with Api suffix, .ts extension
myFeatureApi.ts
postApi.ts
userApi.ts
Helpers/Utilities
Pattern: camelCase with descriptive name, .ts extension
myFeatureHelpers.ts
validation.ts
transblogers.ts
constants.ts
Types
Pattern: camelCase, index.ts or descriptive name
types/index.ts
types/post.ts
types/user.ts
When to Create a New Feature
Create New Feature When:
- Multiple related components (>3)
- Has own API endpoints
- Domain-specific logic
- Will grow over time
- Reused across multiple routes
Example: features/posts/
- 20+ components
- Own API service
- Complex state management
- Used in multiple routes
Add to Existing Feature When:
- Related to existing feature
- Shares same API
- Logically grouped
- Extends existing functionality
Example: Adding export dialog to posts feature
Create Reusable Component When:
- Used across 3+ features
- Generic, no domain logic
- Pure presentation
- Shared pattern
Example: components/SuspenseLoader/
Import Organization
Import Order (Recommended)
// 1. React and React-related
// 2. Third-party libraries (alphabetical)
// 3. Alias imports (@ first, then ~)
// 4. Type imports (grouped)
// 5. Relative imports (same feature)
Use single quotes for all imports (project standard)
Public API Pattern
feature/index.ts
Export public API from feature for clean imports:
// features/my-feature/index.ts
// Export main components
// Export hooks
// Export API
// Export types
Usage:
// ✅ Clean import from feature index
// ❌ Avoid deep imports (but OK if needed)
Directory Structure Visualization
src/
├── features/ # Domain-specific features
│ ├── posts/
│ │ ├── api/
│ │ ├── components/
│ │ ├── hooks/
│ │ ├── helpers/
│ │ ├── types/
│ │ └── index.ts
│ ├── blogs/
│ └── auth/
│
├── components/ # Reusable components
│ ├── SuspenseLoader/
│ ├── CustomAppBar/
│ ├── ErrorBoundary/
│ └── LoadingOverlay/
│
├── routes/ # TanStack Router routes
│ ├── __root.tsx
│ ├── index.tsx
│ ├── project-catalog/
│ │ ├── index.tsx
│ │ └── create/
│ └── blogs/
│
├── hooks/ # Shared hooks
│ ├── useAuth.ts
│ ├── useMuiSnackbar.ts
│ └── useDebounce.ts
│
├── lib/ # Shared utilities
│ ├── apiClient.ts
│ └── utils.ts
│
├── types/ # Shared TypeScript types
│ ├── user.ts
│ ├── post.ts
│ └── common.ts
│
├── config/ # Configuration
│ └── theme.ts
│
└── App.tsx # Root component
Summary
Key Principles:
- features/ for domain-specific code
- components/ for truly reusable UI
- Use subdirectories: api/, components/, hooks/, helpers/, types/
- Import aliases for clean imports (@/, ~types, ~components, ~features)
- Consistent naming: PascalCase components, camelCase utilities
- Export public API from feature index.ts
See Also:
- component-patterns.md - Component structure
- data-fetching.md - API service patterns
- complete-examples.md - Full feature example