Start With the Right Folder Structure

Start With the Right Folder Structure

Open an unfamiliar project and the first thing you read is not the code. It is the list of folders. Before a single file is opened, the layout has already told you what its authors thought mattered, or that nobody thought about it at all.

Structure is cheap to get right on the first day and expensive to fix later, because by then every path in the code, the deployment scripts and the team's habits depend on it. Three rules cover most small projects.

Separate what changes often from what does not

The parts of a project change at very different speeds. Application code changes every week. Configuration changes when the environment does. Third-party packages change when you upgrade them, and nobody should edit them by hand. Uploads, logs and caches change constantly, and they belong to the running system, not to the source code.

Give each its own folder and the boundaries start doing work for you. A deployment can replace the code without touching the uploads. A backup can concentrate on the data that cannot be recreated. A new developer can see which folders are theirs to edit. Mix uploads in with the templates, and one careless deploy can delete a customer's files along with the old version of the site.

Keep secrets and build output out of the repository

Two kinds of file should never be committed. The first is secrets: database passwords, API keys, mail credentials. Keep them in an environment file the code reads at startup, leave that file out of version control, and commit an example copy with the same keys and dummy values, so the next person knows what to fill in. A secret that reaches the repository stays in its history after the file is deleted, so the only real fix is to change the secret.

The second is anything a tool can regenerate: installed packages, compiled assets, caches. They bloat the repository, fill diffs with noise and drift out of step with the files they came from. Commit the recipe (the dependency file and its lock file) and let each machine build its own.

At the end of a project I hand over three things: the code, the credentials and a runbook in plain English. A layout that keeps secrets out of the code is what lets those stay separate. The repository can be shared freely, and the credentials go only to the people who need them.

One obvious entry point

A project should have one front door, and nobody should have to search for it. In a PHP web project that usually means a single index.php inside a public folder that the web server uses as its document root, with everything else (code, configuration, templates, the environment file) one level up, where the server cannot hand it out even if something is misconfigured. In a small Python web app the front door might be one app.py, or a wsgi.py that the server starts.

Some shared hosts fix the document root and give you nothing above it. Then the private folders have to be closed off with server rules instead, and it is worth testing that they really are unreachable rather than assuming so.

A layout for a small PHP project

Here is a starting point for a small web app, say a portal where clients log in and download their documents. It is invented for this post and deliberately boring:

client-portal/
  public/            web root: the only folder the server exposes
    index.php        the one entry point
    assets/          CSS, JavaScript, images
  src/               application code, changes often
  templates/         what the pages look like
  config/            settings, read from the environment
  storage/           uploads, logs, cache (written at runtime)
  tests/
  vendor/            Composer packages (installed, never committed)
  .env               secrets (never committed)
  .env.example       same keys, dummy values (committed)
  .gitignore
  composer.json
  composer.lock
  README.md          how to run it, in plain English

Each folder answers one question: where requests start, where the logic lives, what the pages look like, and what the running system writes. A Python version looks almost the same, with the application package in place of src, a requirements file in place of composer.json, and the virtual environment folder in the ignore list.

Seeing the shape

Rules like these are easy to agree with and hard to check, because you cannot reason about a codebase whose shape you cannot see, and from inside one folder you cannot see it. Project Folder Structure Pro, on my projects page, exists for that problem. Upload a project and it draws an interactive tree of the whole hierarchy, every directory and file however deeply nested, so the structure becomes something you scan rather than something you hold in your head while clicking through folders.

That is useful at both ends of a project. With an inherited codebase, the tree answers the first questions before any code is read: where requests begin, where configuration lives, which folders hold most of the code. On your own project it is a quick honesty check. If the picture surprises you, the layout is saying something you had not noticed.

A good structure passes one test: a stranger can find the entry point, the configuration and the folders they must never edit within a minute of opening the project.