Folders and files
A Kestello site and the Kestello development repository have almost the same layout. This page explains each folder, who writes to it, and whether updates touch it.
A site
site/
├── bin/cms command line entry point
├── config/ the site's configuration (written by the installer)
├── content/
│ ├── plugins/<slug>/ installed plugins
│ ├── themes/<slug>/ installed themes
├── core/
│ ├── current.php names the running release, e.g. return '0.2.0';
│ └── releases/<version>/ Kestello itself, one folder per release
├── public/
│ ├── index.php web entry point
│ └── .htaccess
├── storage/ everything Kestello writes at run time
└── .htaccess for hosts whose document root cannot be public/| Folder | Written by | Touched by updates |
|---|---|---|
bin/, public/ | Nobody after installation. Both entry points only find the running core release and hand over to it. | No |
config/ | The installer, key:generate, and you. | No |
content/plugins/, content/themes/ | Installs and updates of plugins and themes. | Only the package being updated |
core/ | Core updates: a new folder under releases/, then current.php is switched. | Yes, and only this |
storage/ | Kestello at run time. | No |
A development checkout has no core/current.php. Without it, the entry points load core/ directly, which is what you want while working on Kestello itself.
config/
| File | Holds |
|---|---|
app.php | Site name, address, timezone, debug mode, the secret key, and optional sections such as packages and updates. |
database.php | The database connection. |
installed.php | The date and version of installation. Its presence is what tells Kestello the site is installed. |
platform.php | Optional. Infrastructure settings you want fixed in a file (see below). |
Sites installed with early versions may also have a cache.php. Nothing reads it any more: the cache store is an infrastructure setting like the others, and the file can be deleted.
Core's defaults live in core/config/ inside each release. For infrastructure settings (cache, sessions, queue, search, storage, mail, logs) there are four layers, and the first one that sets a value wins:
- environment variables, such as
KESTELLO_CACHE_DRIVER, - files in the site's
config/, such asconfig/platform.php, - what an administrator saved under System → Infrastructure,
- core's defaults.
A value set in an environment variable or a config file shows as locked in the admin, with its source.
The database connection and the secret key are read before the database is, so they come only from config/database.php and config/app.php. To keep them out of the files, read environment variables inside those files with getenv(); see the configuration reference. Kestello then leaves config/app.php alone when general settings are saved in the admin, instead of writing the file back.
storage/
| Folder | What is in it |
|---|---|
storage/app/ | The local storage disks: media (the media library, served at /uploads), public (served at /files), private and backups. |
storage/cache/ | The file cache. Safe to delete. |
storage/compiled/ | Compiled files. Safe to delete. |
storage/database/ | SQLite databases, when SQLite is used. |
storage/fonts/ | Web fonts the site serves itself (downloaded once from the theme builder). |
storage/forms/ | Files visitors attached to form submissions, kept privately and downloaded from Submissions. |
storage/framework/ | Run-time state: maintenance mode, locks, the compiled platform settings. |
storage/logs/ | Log files. |
storage/plugins/ | Files plugins keep. |
storage/sessions/ | Session files, when sessions are stored on disk. |
storage/tmp/ | Uploads waiting for review, staged packages. Cleaned automatically. |
A plugin
content/plugins/acme-events/
├── plugin.json manifest: name, version, requirements, permissions
├── src/ PHP classes, autoloaded from the declared namespace
│ └── EventsProvider.php the service provider named in plugin.json
├── database/migrations/ migrations, run on activation and on upgrade
├── resources/js/
│ ├── pages/ Vue page components: @acme-events/<Name>
│ └── components/
├── assets/build/ built Vue output (committed, shipped in the package)
└── vite.config.js build settings for the plugin's componentsThe hello example plugin uses every part of this layout: a route, a Vue page, a migration, an API endpoint, an event listener, a command, a background job and admin screens. The catalog plugin next to it adds templates/, patterns/ and tests/.
A theme
content/themes/acme/
├── theme.json manifest; may name a parent theme
├── styles.json design tokens: colours, fonts, spacing
├── src/ PHP, if the theme has a provider
├── resources/js/ page and block components
├── patterns/ ready-made block arrangements
├── assets/ fonts, images, built output
└── tools/ build helpers (not needed at run time)A child theme (the base-child example) names its parent in theme.json and only contains what it changes.
The development repository
The repository is a site with a few extra folders:
| Folder | What it is |
|---|---|
core/ | Kestello itself, run directly (no current.php). |
core/src/ | PHP, namespace Kestello\: Framework/, Contracts/, Support/, Cms/ (the modules). |
core/resources/js/ | The admin app (app/), pages, layouts, @kestello/ui (ui/) and @kestello/sdk (sdk/). |
core/resources/assets/build/ | Built front-end files. Committed, so servers never need Node.js. |
core/build/ | The Vite build script. |
core/ssr/ | The optional server-side rendering process. |
core/database/migrations/ | Core migrations. |
docker/, docker-compose.yml | The local development environment. |
tests/ | The test suite. |
Example plugins and themes are in kestellohq/examples, first-party plugins such as Meilisearch, Typesense and Social Login in kestellohq/plugins, and this documentation in kestellohq/docs.