Feature-Based Folder Structure
Organise code by feature domain rather than by type, colocate tests, styles, and components, and enforce boundaries with eslint-plugin-boundaries.
Feature-Based Folder Structure is a free Frontend Academy lesson on CoddyKit — lesson 4 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Frontend Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
Two Ways to Organise Code
You can group code by type (components/, hooks/, services/, types/) or by feature (auth/, checkout/, dashboard/ — each containing its own components, hooks, etc.). Feature-based wins for medium-to-large apps.
Type-Based — The Default Trap
The classic React tutorial structure groups everything by type. It scales badly: every file change touches multiple unrelated folders, and 'find all checkout code' means greping across the whole tree.
// Type-based (avoid for large apps):
src/
components/
Button.tsx
LoginForm.tsx
CartItem.tsx
hooks/
useAuth.ts
useCart.ts
services/
auth.ts
cart.ts
types/
User.ts
CartItem.tsFeature-Based Structure
Group everything related to a feature in one folder. Easy to find, easy to delete, easy to reason about.
src/
features/
auth/
LoginForm.tsx
SignupForm.tsx
useAuth.ts
auth.service.ts
auth.types.ts
auth.test.tsx
cart/
CartItem.tsx
CartSummary.tsx
useCart.ts
cart.service.ts
cart.types.ts
shared/
components/
Button.tsx
hooks/
useDebounce.tsCo-location Inside a Feature
A feature folder contains: components, hooks, services, types, tests — all the code needed for that domain. New developer wants to understand auth? Open auth/. Want to delete auth? Delete the folder.
Shared vs Feature
Code used by 2+ features moves to shared/ (or lib/). Code used by one feature stays inside it. Resist 'might be reusable later' — wait for the second use before extracting.
Feature Boundary Rules
Features should not import from each other directly. If two features need to share code, the shared piece moves to shared/. If they need to coordinate, use events or a shared store at the app level.
Enforcing Boundaries with ESLint
Use eslint-plugin-boundaries or eslint-plugin-import to enforce: features can import from shared but not from each other.
// .eslintrc.json
{
"plugins": ["boundaries"],
"settings": {
"boundaries/elements": [
{ "type": "feature", "pattern": "src/features/*" },
{ "type": "shared", "pattern": "src/shared/*" }
]
},
"rules": {
"boundaries/element-types": ["error", {
"default": "disallow",
"rules": [
{ "from": "feature", "allow": ["shared"] },
{ "from": "shared", "allow": ["shared"] }
]
}]
}
}Public API per Feature
Each feature exports a public API via features/auth/index.ts. Other code imports from '@/features/auth', not deep paths. Lets you refactor internals without breaking consumers.
// features/auth/index.ts
export { LoginForm } from './LoginForm';
export { useAuth } from './useAuth';
export type { User, AuthState } from './auth.types';
// Consumers:
import { LoginForm, useAuth } from '@/features/auth';
// NOT: import { LoginForm } from '@/features/auth/LoginForm';Nesting Subfeatures
Large features can have subfolders: dashboard/widgets/, dashboard/charts/. Avoid nesting deeper than 2-3 levels — search becomes painful.
Where Routes Live
Pages/routes can live in a top-level pages/ or routes/ folder. They're thin — they pull components and hooks from features and compose them.
src/
pages/
Dashboard.page.tsx // composes Dashboard widgets from features/dashboard/
Cart.page.tsx // composes from features/cart/
features/
shared/Migrating an Existing App
Start with new features only — put new code in features/. Don't refactor everything at once. As you touch old files, gradually move them. ESLint boundary rules prevent regression in the new structure.
When Type-Based Still Works
For very small apps (under 30 components) or libraries, type-based is fine. Use feature-based as soon as you have distinct business domains (auth, checkout, billing, settings).
Quick Check
What's the main organisational benefit of grouping code by feature instead of by file type?
Recap: Feature-Based Structure
features/ contains domain-specific code; shared/ contains cross-feature utilities. Each feature exports a public index.ts. Features don't import from each other — only from shared. Enforce with eslint-plugin-boundaries. Pages/routes compose features. Migrate incrementally. Type-based is fine for small apps.
Frequently asked questions
Is the “Feature-Based Folder Structure” lesson free?
Yes — the full text of “Feature-Based Folder Structure” is free to read here on the web, and the Frontend Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Frontend Academy course, upgrade to CoddyKit PRO.
What will I learn in “Feature-Based Folder Structure”?
Organise code by feature domain rather than by type, colocate tests, styles, and components, and enforce boundaries with eslint-plugin-boundaries. You practise Frontend Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start Frontend Academy?
No prior experience is required. Frontend Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 4 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “Feature-Based Folder Structure” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this Frontend Academy lesson?
Yes. Every Frontend Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- Atomic Design: Atoms Molecules Organisms
- Monorepo Setup with Turborepo
- Micro-frontends: Module Federation
- Feature-Based Folder Structure