RU Send your project
All articles

Project Structure: How to Organise Files and Folders

Project structure in plain terms: feature folders vs layers, and where config, UI, logic and data access should live so neither you nor the AI gets lost.

· 5 min readCodeBasics

Project structure is how files and folders are laid out in a repository: where the UI lives, where the logic lives, where database code and settings go. A good structure answers “where is this?” before you finish asking.

In vibe-coded projects, structure tends to happen by accident. The AI creates each file wherever is convenient at that moment, and a couple of months later the components folder holds buttons, database queries and price calculations side by side. It works, right up until a change requires finding every place the price is calculated.

Why it matters when an AI writes the code

An AI assistant doesn’t remember your project between sessions. Each time, it looks at the folder tree afresh and guesses where to put things and where to look for them. With a predictable structure, it guesses right. Without one, it writes a fourth copy of a function because it couldn’t find the first three.

The same goes for people. A new developer understands how a project is organised from its structure before opening a single file. Or doesn’t.

Folders by layer or by feature

There are two main approaches.

By layer: everything of one type together, as in components/, hooks/, services/, api/, types/. Plenty of templates and tutorials work this way. It’s fine in a small project, but as it grows each feature gets smeared across five folders, and changing billing means opening files in all five.

By feature: everything about one part of the product together, as in billing/, profile/, projects/. Inside a feature you can still split UI, logic and data. Changing billing means working in one folder.

For products bigger than a few screens, we recommend features on top and layers inside. Roughly:

src/
  features/
    billing/
      ui/          components and pages
      logic.ts     rules: what's allowed, what it costs
      data.ts      database and API calls
    projects/
      ...
  shared/
    ui/            buttons, inputs, modals
    lib/           shared utilities
  config/          reading environment variables
  db/              schema and migrations

The exact names don’t matter. What matters is that there’s one rule and it’s followed everywhere.

Where things live

Configuration. Environment variables are read in one place, validated at startup, and passed on as plain values from there. If process.env appears in twenty files, nobody knows which variables the project actually needs.

UI. Components display data and report what the user did. They don’t query the database directly and don’t decide what a subscription costs. Shared elements like buttons, inputs and modals live apart from features, because everyone uses them.

Logic. The product’s rules: who can do what, how prices are calculated, when access expires. This is the most valuable code you have, and the easiest to test, as long as it isn’t tangled up with UI and queries.

Data access. Database and external API calls sit in their own modules with clear functions like getProjectsForUser(userId). That way permission checks live in one place instead of being repeated in every component with varying success.

Server versus client. Code that touches secrets and the database must live where it can’t end up in the browser. Many frameworks mark this with a dedicated folder or a directive at the top of the file. Find out how yours does it and stick to it.

Moving over without stopping work

You don’t need to redo everything over a weekend. Agree on the target structure and write it down in the README and in the instructions file for your AI assistant (CLAUDE.md, .cursorrules or similar). Then move one feature at a time, usually starting with the one you touch most often. One move per commit, with no logic changes mixed in, so it’s easy to confirm nothing broke.

New code goes into the new structure from day one. A month later, little of the old layout is left, and you can finish it off.

Signs your project structure isn’t working

  • You find files by search, not by browsing the tree.
  • There’s a thousand-line utils.ts.
  • The same logic exists in two or three places with small differences.
  • Changing one feature means touching more than five folders.
  • The AI keeps creating files somewhere other than where you expected.

In short

  • Project structure is the answer to “where is this?”, readable by both you and the AI.
  • For products beyond a few screens, features on top with layers inside work best.
  • Config is read in one place, UI doesn’t touch the database, logic is separate from queries.
  • Write the target structure into the README and your AI assistant’s instructions.
  • Migrate one feature per commit, and put new code in the new structure straight away.

SUBXCAT helps sort out an overgrown project without putting product work on hold.

Want us to do this for you?

Tell our assistant about your project — a rough estimate in five minutes, a review in 48 hours.

Book an intro call 20 minutes: an engineer, a designer and a marketer look at your project with you.
Book a call