Mahamudul Hasan Rubel
HomeAboutProjectsSkillsExperienceBlogPhotosContact
Mahamudul Hasan Rubel

Senior Software Engineer crafting high-performance web applications and SaaS platforms.

Navigation

  • Home
  • About
  • Projects
  • Skills
  • Experience
  • Blog
  • Photos
  • Contact

Get in Touch

Available for senior/lead roles and consulting.

bd.mhrubel@gmail.comHire Me

© 2026 Mahamudul Hasan Rubel. All rights reserved.

Built with using Next.js 16 & Tailwind v4

Back to Blog
ReactNext.jsJune 22, 20264 min read

React component architecture: Mastering Colocation for Better Maintainability

React component architecture thrives on colocation. Learn why grouping logic, state, and UI by feature beats file-type organization for scalable Next.js apps.

ReactNext.jsFrontend ArchitectureClean CodeWeb DevelopmentTutorial

I remember the exact moment I realized my project structure was a disaster. I was working on a dashboard feature in a medium-sized Next.js app, and I spent about 15 minutes just jumping between four different folders—components/, hooks/, styles/, and utils/—just to change the color of a button and the validation logic for its parent form.

When you’re starting out, following the "standard" folder-by-type structure feels organized. But as your application grows to include 50+ components, that structure becomes a tax on your brain. You aren't coding; you're playing "find the file."

Why React component architecture needs colocation

The core problem with grouping by file type is that it separates things that change together. If you’re modifying a feature, you’re almost always touching the UI, the state logic, and the styles simultaneously.

When you embrace colocation, you group files based on the feature they serve. Instead of a massive hooks/ folder, you have a features/user-profile/ directory containing the component, its specific hooks, its styles, and even its local tests.

This shift isn't just about tidiness. It’s about cognitive load. When I open a feature folder, I want to see everything that makes that feature tick in one place. If you're struggling with state flow, you might want to review React state management: Mapping Your Next.js Component Hierarchy to see how this physical layout mirrors your data flow.

The wrong turn: Over-abstracting too early

Early in my career, I tried to make everything "reusable." I’d take a button, a label, and a fetch hook and move them into a global shared/ folder because "I might need this in another page."

It broke my flow. Every time I needed to tweak the button, I had to worry about breaking five other pages. I spent more time maintaining the "shared" abstraction than building the product.

Now, I follow the "Rule of Three":

  1. Keep the code inside the feature folder.
  2. If you need it in a second place, keep it there but keep an eye on it.
  3. Only move it to a shared library once you’ve used it in three distinct places.

Implementing a better Next.js folder structure

When you're building a modern app, your Next.js folder structure should prioritize discoverability. I usually organize my src/ directory like this:

TEXT
src/
  app/
    (dashboard)/
      page.tsx
      layout.tsx
  features/
    user-settings/
      components/
        SettingsForm.tsx
        AvatarUploader.tsx
      hooks/
        useSettings.ts
      user-settings.test.ts
      index.ts

By exporting only what you need from the index.ts file in the feature folder, you keep your imports clean. You don't have to worry about the internal implementation details of the user-settings module from your app/ directory.

Managing state within the feature

One common concern juniors have is: "If I colocate, where does my global state go?"

The answer is: keep it as close to where it’s consumed as possible. If you’re using React Context or simple useState, don't feel obligated to put it in a global store/ directory. If it’s only used by the user-settings feature, it lives inside that feature's hooks/ folder.

If your state logic is getting messy, it’s usually not because of the folder structure, but because the logic is too complex for a simple hook. That’s when you might look at TypeScript State Machines: Building Predictable UI Logic with XState to formalize your transitions.

The trade-offs of colocation

Is colocation perfect? No. You’ll eventually have folders that feel slightly bloated. Sometimes, a feature grows so large that it deserves to be its own micro-app or package.

However, the alternative—a components/ folder with 200 files—is almost always worse. When files are scattered, you lose track of the "why" behind the code. You see a useFetch.ts hook but have no idea which component it was designed for, leading to weird bugs during re-renders. If you're running into those issues, check out React rendering: Mastering State Batching and the Two-Pass Model to understand how your local state lifecycle works.

Frequently Asked Questions

Q: Does colocation make it harder to find shared components? A: Not if you use an index.ts file to manage your public API. Treat your feature folders like internal modules. If you need something globally, move it to a components/ui/ folder, but only after you’ve verified it’s truly generic.

Q: Should I put my unit tests inside the feature folder? A: Absolutely. Having the test right next to the component makes it 10x more likely that you’ll actually run the test and keep it updated. If the test is in a separate __tests__ directory at the root, it’s out of sight and out of mind.

Q: Is this overkill for small projects? A: Maybe. For a landing page, a flat structure is fine. But I’ve found that even in small projects, starting with a feature-based structure prevents the "refactor-nightmare" that happens when a project suddenly doubles in size.

I'm still experimenting with how to handle shared styles across different features. Sometimes I use CSS modules, sometimes Tailwind, and the boundaries can get blurry. Don't stress about being perfect. Just focus on keeping the code that belongs together, together. Your future self will thank you when you don't have to hunt through five directories to fix one line of logic.

Back to Blog

Similar Posts

ReactNext.jsJune 22, 20264 min read

React rendering: Tracing Prop Changes from Update to DOM Patch

React rendering pipeline demystified: Learn how a prop change triggers reconciliation and DOM patching to keep your UI in sync with your component state.

Read more
ReactNext.js
June 22, 2026
4 min read

Next.js Streaming SSR: Architecting Progressive Payload Serialization

Next.js Streaming SSR and progressive payload serialization can drastically reduce latency. Learn how to optimize data graphs for faster, smoother delivery.

Read more
ReactNext.jsJune 22, 20264 min read

React derived state: Stop using useEffect for data calculations

React derived state is the key to faster components. Learn how to stop abusing useEffect for data transformations and simplify your React performance optimization.

Read more