# Collocation on the Frontend Web: Why It Matters and How I Do It in Next.js (or any frontend framework at all)

> "Put things where they’re used." That’s the golden rule of collocation in frontend development, and once I embraced it fully, my Next.js projects became easier to scale, debug, and maintain.

---

## TLDR;

Collocation makes it easier to find everything related to a feature, component or page in your code, whether you want to make an update or remove an entire feature. Your project’s features are more modular and reusable, and onboarding a new developer to your codebase becomes less stressful. 😉

## What is Collocation?

Collocation in frontend web development simply means **placing related files and logic close to each other, or in the same folder or context where they are actually used**.

So instead of scattering styles in one folder, components in another, and tests in another, you keep everything related to a single feature or component tightly grouped.

Think of it like packing for a trip. You don’t keep your toothbrush in your garage and your passport in the kitchen. You group things by purpose. It’s the same idea here, just that we’re now “packing” our code ☺️.

## Why Collocation Matters on the Frontend

In a modern frontend stack, especially with frameworks like **Next.js**, collocation is not just a pattern. It’s a best practice. Why?

* **Discoverability:** Easier to find everything related to a component or page.
    
* **Cognitive simplicity:** No need to mentally map files across the entire tree.
    
* **Testing is easier:** Test files sit next to the components they test.
    
* **Scoped styles and logic:** CSS Modules, hooks, and utils don’t leak across the app.
    
* **Encapsulation:** Your features are modular and reusable.
    

## A Typical Next.js Project Without Collocation

Here’s a simple (and painful) structure I’ve seen too many times:

```markdown
/components  
  Navbar.tsx  
  Button.tsx

/styles  
  Navbar.module.css  
  Button.module.css

/pages  
  index.tsx  
  about.tsx

/tests  
  Navbar.test.tsx  
  Button.test.tsx
```

Now imagine maintaining this at scale. 🥲

## With Collocation

Here’s how I typically structure my Next.js apps now using collocation:

```markdown
my-next-app/
├── src/
│   ├── app/                 # Top-level route components
│   │   └── login/
│   │       ├── layout.tsx
│   │       └── page.tsx
│   │   └── assets/                # Global static assets (images, fonts)
│   │       ├── logo.svg                
│   │       └── favicon.ico
│   │   ├── layout.tsx
│   │   ├── loading.tsx
│   │   └── page.tsx
│   ├── components/            # Shared components
│   │   └── Button/
│   │       ├── Button.tsx
│   │       ├── Button.module.css
│   │       └── Button.test.tsx
│   ├── features/              # Feature-specific modules
│   │   └── auth/
│   │       ├── components/
│   │       │   ├── Login.tsx
│   │       │   ├── Login.module.css
│   │       │   └── Login.test.tsx
│   │       ├── hooks/
│   │       │   └── useAuth.ts
│   │       ├── services/
│   │       │   └── authService.ts
│   │       └── types.ts
│   ├── hooks/                 # Global reusable hooks
│   │   └── useMediaQuery.ts
│   ├── layouts/               # Layout components (e.g., MainLayout)
│   │   └── MainLayout.tsx
│   ├── types/                 # Global type declarations
│   │   └── index.d.ts
│   ├── utils/                 # Utility functions
│   │   └── formatDate.ts
│   └── middleware.ts          # Middleware component
├── .gitignore
├── package.json
├── tsconfig.json
├── next-env.d.ts
└── next.config.mjs
```

Let’s break it down:

* Each route (like `/login`) has its own folder with its page component and supporting components in the features folder. Now, this is because I prefer not to have my component and logic files in the app folder. You can also decide to move you feature-specific folder to the feature/route folder in the app directory if you prefer them that close.
    
    Like this;
    
    ```markdown
    /app/login/
      page.tsx
      layout.tsx
      Login.tsx
      Login.module.css
      Login.test.tsx
      useAuth.ts
    ```
    
* **Styles**, **tests**, and **local hooks** sit right next to the components they belong to.
    
* Shared UI components or layout wrappers go into `components` folder.
    
* Shared utils go in `utils`.
    

It’s clean, it’s local and, it scales!

## Bonus: A Vite App With Collocation

```markdown
my-vite-app/
├── public/                    # Static assets
│   └── favicon.svg
├── src/
│   ├── assets/                # Global static assets (images, fonts)
│   │   └── logo.svg
│   ├── components/            # Shared components
│   │   └── Button/
│   │       ├── Button.tsx
│   │       ├── Button.module.css
│   │       └── Button.test.tsx
│   ├── features/              # Feature-specific modules
│   │   └── auth/
│   │       ├── components/
│   │       │   └── LoginForm.tsx
│   │       ├── hooks/
│   │       │   └── useAuth.ts
│   │       ├── services/
│   │       │   └── authService.ts
│   │       └── types.ts
│   ├── hooks/                 # Global reusable hooks
│   │   └── useMediaQuery.ts
│   ├── layouts/               # Layout components (e.g., MainLayout)
│   │   └── MainLayout.tsx
│   ├── pages/                 # Top-level route components
│   │   └── Home/
│   │       ├── Home.tsx
│   │       └── Home.module.css
│   ├── routes/                
│   │   └── index.tsx
│   ├── types/                 # Global type declarations
│   │   └── index.d.ts
│   ├── utils/                 # Utility functions
│   │   └── formatDate.ts
│   ├── App.tsx                # Root component
│   ├── main.tsx               # Vite entry point
│   └── vite-env.d.ts          
├── .gitignore
├── index.html
├── package.json
├── tsconfig.json
├── tsconfig.node.json
└── vite.config.ts
```

## A Collocation Example in Code

Say I have a `Hero` section in my homepage. Here’s what that folder might look like:

### Hero.tsx

```typescript
import styles from './hero.module.css';
import { useHeroData } from './useHeroData';

export default function Hero() {
  const { title, subtitle } = useHeroData();
  return (
    <section className={styles.hero}>
      <h1>{title}</h1>
      <p>{subtitle}</p>
    </section>
  );
}
```

### useHeroData.ts

```typescript
export function useHeroData() {
  return {
    title: 'Welcome to My Site',
    subtitle: 'Frontend, Fast, and Beautiful',
  };
}
```

Everything lives in one place. If I ever need to update or remove the `Hero`, I know **exactly** what to touch.

Also, if I need to remove an entire feature, I know where to go and not leave any unused code behind.

## Pro Tip: Collocation ≠ Coupling

A lot of people confuse collocation with tight coupling. Nope.

You can still keep components modular and testable while collocating. You're just being smarter at putting tools next to the task.

**PS:** Coupling speaks to how much one component or module depends on another in a project. For your components to be tightly coupled means that you have components that are heavily connected or dependent on one another and changing one often breaks the other.

I’ll be writing more about this later! 🙃

## Summary

Collocation is like flossing; everyone agrees it’s good for you, but only a few people do it consistently. Once I made it a rule in my Next.js workflow, things got really smoother.

🥂 Fewer bugs.  
👌 Fewer mental jumps.  
💪 Better developer experience.

If you’re starting a new project, collocate from day one. If you're refactoring an old one, do it incrementally and I promise you won’t regret it!
