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:
| Folder | What 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 |
Key files inside app/Config/
Three configuration files come up constantly throughout this track, so it's worth naming them now:
| File | Responsible for |
|---|---|
app/Config/Routes.php | Every route definition in your application (full lesson: Routing) |
app/Config/Database.php | Database connection settings — host, driver, credentials, database name |
app/Config/App.php | Application-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.
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.
| Subfolder | Purpose |
|---|---|
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.
app/Config/Routes.php maps
URLs to controller methods, including CodeIgniter's automatic routing convention.