A feature-first approach to building scalable, maintainable, and predictable React applications with TypeScript. Designed for clarity, consistency, and efficiency, this guide minimizes cognitive load and enforces best practices.
- Feature-First Development - Features are self-contained and organized around routes.
- Minimal Cognitive Load - Engineers should immediately know where code belongs.
- Predictability & Consistency - Every feature follows the same structure.
- No Unnecessary Abstractions - Complexity is only introduced when necessary.
- Automation Over Convention - Enforceable via ESLint/Prettier instead of manual rules.
Additional Resources:
A feature is a self-contained module that represents:
- A route (
/guides/:guideId) - A significant UI section
- Reusable business logic specific to a domain
pages/guides/search → Feature (route: `/guides/search`)
GuideSearch.tsx → Main component
pages/guides/:guideId → Feature (route: `/guides/:guideId`)
Guide.tsx → Main component
hooks/useGetGuideQuery.ts → Query for getting details
hooks/useGuideMetricShare.ts → Handles copy-to-clipboard/sharing
components/GuideHero.tsx → Feature-scoped component
pages/profile/:accountHandle → Feature (route: `/profile/:accountHandle`)
Profile.tsx → Main component
pages/profile/:accountHandle/guides → Feature (route: `/profile/:accountHandle/guides`)
ProfileGuides.tsx → Main component
- Flat structure: No deep nesting inside features.
- Feature-scoped: Hooks and components belong inside the feature they support.
- No
common/folder - Instead, usesrc/hooks/for sitewide hooks andsrc/components/for reusable components.
Ordering Inside a Component:
- Hooks (
useState,useEffect, etc.) - Local Variables (constants, derived values)
- useEffect Hooks (side effects, lifecycle logic)
- Event Handlers & Functions
- Return Statement (JSX)
Example Component:
export const Profile = () => {
const { hasError, isLoading, profileData } = useGetProfileQuery()
if (isLoading) return <ProfileLoading />
if (hasError) return <ProfileEmpty />
return (
<section>
<ProfileHero />
<ProfileContent />
</section>
)
}| Item | Naming Convention |
|---|---|
| Variables, Functions, Hooks | camelCase (e.g., getUserProfile) |
| Components, Enums, Interfaces | PascalCase (e.g., UserProfileCard) |
| Folders | kebab-case (e.g., profile-settings/) |
| Constants | Defined within feature files, not in a global folder. |
| GraphQL Queries/Mutations | camelCase inside operations, PascalCase for file names |
| Type | Placement |
|---|---|
| Feature-based Queries | Inside pages/featureName/hooks/ |
| Sitewide Queries | Inside src/hooks/ |
Correct Naming Examples:
query GetGuide($id: ID!) { ... } # Fetches full guide details
query GetGuideEvents($guideId: ID!) { ... } # Fetches related guide events
query GetGuideImages($guideId: ID!) { ... } # Fetches guide imagesAdditional Resources:
| When to Use | Rule |
|---|---|
| Props for Components | Use interface (e.g., interface ProfileProps {}) |
| Everything Else (Utilities, Hooks, GraphQL, API Responses) | Use type (e.g., type UseGetProfileQueryResult = {}) |
| Extracting Subsets of Types | Use Pick<> and Omit<> |
Additional Resources:
| Item | Rule |
|---|---|
| Storage | Centralized in config/feature-flags/featureFlags.ts |
| Usage | Accessed via useFlag hook |
| Cleanup | Feature flags should be short-lived |
Additional Resources:
- Code should be self-explanatory; avoid unnecessary comments.
- Use JSDoc
@todofor tracking future work. - Only document "why", not "what" the code does.
Example:
/** @todo Remove this workaround when the new API version is available */
const getUserPreferences = async (userId: string) => {
return await fetch(`/api/preferences/${userId}`)
}Additional Resources:
This cheat sheet ensures clarity, predictability, and minimal cognitive load.
- Keep rules minimal & enforceable.
- Follow automation-first principles.
- Structure code in a way that scales naturally.
This is your definitive React + TypeScript Feature-First Style Guide, designed to reduce thinking, improve efficiency, and create scalable applications effortlessly.