Directory Structure

The previous page listed the top-level folders of a fresh CodeIgniter 4 install at a glance. Here we go deeper: what lives inside app/, why public/ is the only folder your webserver should ever expose, why writable/ needs special file permissions, and how a single HTTP request actually travels through all of this to produce a response.

1. Inside app/

Almost everything you write as an application developer lives inside app/. It is organized by responsibility, which is what makes CodeIgniter's MVC structure easy to navigate once you know the map:

FolderWhat goes here
app/Controllers/Controller classes — the entry point for each request, responsible for coordinating models and views
app/Models/Model classes that talk to the database via CodeIgniter's Query Builder (covered in depth on the Models & Query Builder page)
app/Views/View files — PHP templates responsible only for presentation/HTML output
app/Config/Configuration classes: Routes.php, Database.php, App.php, and many more
app/Helpers/Your own procedural helper functions, loaded on demand with helper()
app/Libraries/Custom service classes that don't fit the Model/Controller mould — reusable business logic you write yourself
Foreshadowing: Helpers and Libraries get their own dedicated lesson later in this track (Helpers & Libraries), since there's enough nuance there — loading helpers, autoloading them globally, writing your own library classes — to warrant a full page.

Key files inside app/Config/

Three configuration files come up constantly throughout this track, so it's worth naming them now:

FileResponsible for
app/Config/Routes.phpEvery route definition in your application (full lesson: Routing)
app/Config/Database.phpDatabase connection settings — host, driver, credentials, database name
app/Config/App.phpApplication-wide settings such as base URL, default locale, and CSP options

2. public/ Is the Real Web Root

This is one of the most important structural decisions in CodeIgniter 4, and it matters for security, not just organization: your webserver's document root should point at the public/ folder, and nothing else. Inside public/ you'll find index.php (the single front-controller entry point for every request) plus your publicly servable assets — CSS, JavaScript, images.

Why this matters: Everything outside public/ — your app/ code, your .env file with database credentials, your vendor/ dependencies — sits outside the web-accessible folder entirely. Even if your server were misconfigured to allow directory browsing, there is no application logic or secret sitting in a place a browser could ever request directly. Compare this to a plain PHP app where everything lives in one browsable folder — a single misconfiguration there can expose source code or credentials.

In practice, a production virtual host configuration points its DocumentRoot straight at the public/ folder:

DocumentRoot "/var/www/my_project/public"

3. The writable/ Folder

writable/ is where CodeIgniter stores everything it needs to write to disk while your application runs: compiled cache files, session data (if you use file-based sessions), application logs, and any files your app lets users upload. Because the framework writes here on every request that needs it, this folder (and its subfolders) must be writable by whatever user your webserver process runs as.

SubfolderPurpose
writable/cache/Page and data caching
writable/logs/Application error and debug logs
writable/session/File-based session storage
writable/uploads/A conventional (not enforced) location for user-uploaded files

On a Linux server, granting write access typically looks like this (adjust the owning user/group for your setup):

chmod -R 755 writable/
chown -R www-data:www-data writable/

4. The MVC Request Flow, Step by Step

Every request to a CodeIgniter application, regardless of what it ultimately does, passes through the same pipeline. Understanding this flow makes debugging dramatically easier, because you always know which stage to inspect first.

Browser Request
      |
      v
public/index.php  (front controller, the only PHP file the webserver executes directly)
      |
      v
Routing            (app/Config/Routes.php decides which Controller/method handles this URL)
      |
      v
Controller          (app/Controllers/... - coordinates the request)
      |
      v
Model (optional)     (app/Models/... - talks to the database, returns data)
      |
      v
View                (app/Views/... - renders HTML using data passed from the controller)
      |
      v
Response  --------> back to Browser

Two things are worth calling out about this flow. First, the Model step is genuinely optional — a controller that just renders a static page or returns JSON built inline never has to touch a model. Second, public/index.php is a thin bootstrap file; it doesn't contain your application logic, it simply loads the framework, boots it, and hands control to the routing layer.

Next steps: Now that you know where routes are defined, continue to Routing to see exactly how app/Config/Routes.php maps URLs to controller methods, including CodeIgniter's automatic routing convention.