DEV Community

Angela Pat.
Angela Pat.

Posted on

Frontend Code organization, regardless of the stack in times of AI 🤖

Let's talk about Frontend architecture. We all know that Frontend has become complex with the days and why is it so?
Front-end is where all user requirements, user enhancements, use of the Business domain, handling of errors, optimizations, and much more all come together. Our frontend architecture is responsible for the cohesion of the new and old codebase.

In the time of AI agents 🤖

Even now, with the rise of AI agent coding tools, clean and well organized code remains critical.
Without clear instructions, AI can easily overcomplicate solutions. AI agents understand domain logic through code structure. The clearer and more consistent patterns you have, the less context the Agent holds, because the agent will follow a predictable organization.

For that reason, my rule of thumb is simple: Follow a feature approach to code organization

What is a feature approach?

Also called a modular approach is the practice of breaking down a solution or user requirements into smaller units, where each unit has a single responsibility.

Following this approach helps maintain a solution over the long term and makes it easier to add new features, whether they are simple or complex.

With so many stacks out there, why not use the basic organization offered by a library or framework?

Of course you can! A framework or library often provides a playground or a basic project structure to get you started. However, as tasks grow bigger and features begin to interact with one another, it becomes our responsibility to break down big user requirements or concepts into self-contained units.

A use case:

Let's say your Admin panel website, needs a new feature an Employees overview page with the following use cases:

Page: Employees Overview***
 - Filter (search, role, age range)
 - List employees
 - Open modal for Editing a new employee 
 - Open a modal for adding a new employee
Enter fullscreen mode Exit fullscreen mode

Now, we can design the architecture by breaking the solution into smaller building blocks.

For example:

Rough idea structured in blocks

With our rough idea in place, we can start organizing our code using a feature approach. We take a big feature and split it into smaller and independent blocks called features or modules.

project 
└─── common/            
│       └─── components/
│               └──── Modal
│       └─── hooks/ 
│               └─── useUserLanguage.ts  
│       └─── models/ 
│               └─── user.ts 
└─── core/
│       └─── authentication/
│       └─── i18n/
│       └─── translations/
│       └─── router/
│       └─── api/
│       └─── store/
└───features/
│   └───employees-overview/
|       │─── EmployeesOverview.tsx (Main component)
│       └─── components/
│             └────── employee-filter/
│             └────── employee-list/
│             └────── employee-add/
│             └────── employee-edit/
│                        └────── hooks/
│                                 └───── useFetchUser.ts
│                                 └───── useUpdateUser.ts
│                        └────── components/
│                        └────── helpers/ 
│                        └────── models/  
│                        └────── EmployeeEdit.tsx
└───lib/
│   └───utils

Enter fullscreen mode Exit fullscreen mode

Let me explain you shortly about some of the important folders and what functionality they cover

  • common Also called shared: Contains code that can be reused across features. You can organize them by components, hooks, composables, helpers, etc.
    • helpers Also called functions: Pure functions that performance specific tasks.
    • models: Represent your entities. It's recommended that your entities match the backend for consistency and a single source of truth, with slight differences when needed, for example, dates (the backend uses UTC, while the frontend uses a Date object).
  • features: Feature-based code aligned with your business goals.
  • core (optional): Contains the foundational code of your app. This folder is optional because you can either keep these files in a dedicated core folder, making it easy to find anything your app relies on, or place them directly in your main structure.

  • lib Also called utility functions: Generic technical functions that are not related to domain or business logic and can be used across your code.

Conclusion 💞

Start thinking in terms of features, responsibilities, and blocks and let your team and AI agents maintain the code more easily 💪

Top comments (3)

Collapse
 
peacebinflow profile image
PEACEBINFLOW

This hits a point that I think a lot of people are feeling but not quite articulating yet: AI didn’t make frontend architecture less important — it made bad architecture louder.

What resonated for me is the idea that structure is now part of the interface between humans and AI. We used to organize code mainly so teammates could reason about it. Now there’s a second reader in the room, and it’s extremely literal. If your boundaries are fuzzy, the agent doesn’t “figure it out” — it just starts inventing structure on your behalf. That’s how you end up with over-abstracted components, duplicated logic, and hooks that exist purely because the model needed somewhere to put code.

The modular, feature-first approach you’re describing does two important things at once:

  • For humans, it maps cleanly to business intent (“this is the employees overview, these are its responsibilities”).
  • For AI, it reduces the search space. The agent doesn’t need to hold the entire app in context — it just needs to respect the local contract of the module.

I also like that you didn’t frame this as “framework X vs framework Y.” This works whether you’re in React, Vue, Svelte, or something homegrown. The mistake I keep seeing is people leaning harder into framework defaults as apps grow, when the real scaling move is outgrowing the defaults and organizing around domain boundaries instead of technical ones.

One thing I’d add from my own experience: modularity isn’t just about folders, it’s about permission. A well-defined module implicitly answers questions like:

  • “Where is it allowed to change state?”
  • “What can this feature know about the rest of the system?”
  • “What should never be imported here?”

When those answers are clear, both humans and AI behave better.

So yeah — this isn’t about making AI write prettier code. It’s about designing a codebase that resists entropy, even when you introduce a tool that can generate infinite variations instantly. Clean boundaries are no longer just a quality choice; they’re a control mechanism.

Collapse
 
angelapy profile image
Angela Pat.

I agree with your statements. Glad you took a moment to read this 🌸.

I really like what you said. Agree! Using AI in a bad architecture only makes the problems louder.

Collapse
 
mariaast profile image
Maria • Edited

Amazing work, very helpful!!