Project structure
A site is one folder: your configuration, content and plugins, with Lettern's code beside them. Updates never touch your content.
On this page
A site is one folder, and it is a Composer project however it got there.
#The folder
| Path | What it holds | Commit to git? |
|---|---|---|
index.php, cms, .htaccess | Front controller, command line and Apache rules. Lettern keeps them current. | With Composer: no. They come back on composer install |
setup.php, bundle.json | What a fresh upload uses to fetch the release. Unused once it has run. | No |
composer.json, composer.lock | What this site uses: letterncms/cms and its plugins. | Yes |
vendor/ | Lettern and the libraries it runs on, on a site managed with Composer. | No |
runtime/ | The same vendor/, one folder per release, on a site that updates itself. | No |
plugins/ | The plugins of this site: plugins/<name>, and a third party's in plugins/<vendor>-<name>. Your own go here too. | Only what you wrote |
config/ | site.yaml (name, URL, languages), plugins.yaml (enabled plugins, disabled modules), roles.yaml, admin.yaml (the default sidebar and home arrangement) and one YAML file per settings namespace. | Yes |
config/license.key | The key of a paid plugin, when this site has one. | Yes |
content/design/ | The design system (tokens.json), fonts, custom.css and custom.js. | Yes |
content/collections/ | Collection definitions, and entries of file-based collections โ including templates/ and components/. | Yes |
content/ (the rest) | Fieldsets, globals, forms, menus, redirects. | Yes |
public/ | What visitors get: built pages, uploaded media in media/, and in _cms/ generated images, compiled CSS, fonts and plugin assets. | Media only |
storage/ | Logs, caches, drafts of file-based entries (unpublished template and component changes too), encrypted secrets, the SQLite database. | No |
.env | Database credentials, app key, environment flags. | No |
#Where the code is
Lettern itself is the Composer package letterncms/cms, at vendor/letterncms/cms. You don't edit it, and an update replaces it. It holds:
| Folder | What it holds |
|---|---|
src/ | The kernel: content, users, abilities, the package system, HTTP and CLI. |
modules/ | The admin's modules: the admin itself, content, collections, globals, users, account, audit, home, settings and the Modules screen. |
brand/ | brand.json (the product's name and links), wordmark.svg and mark.svg; see Configuration. |
A site that updates itself keeps that vendor/ in runtime/<version>/vendor/, and the one-line file runtime/current names the release in use. That is how an update goes live and goes back. On a site managed with Composer there is no runtime/, and vendor/ sits in the site folder.
#What to put in git
Commit composer.json, composer.lock, config/, content/ and the plugins you wrote โ the design system, templates, components, collections, global sets, menus, forms and file-based entries are plain JSON, YAML and Markdown that diff nicely. Ignore vendor/, runtime/, storage/, .env, the plugins Composer installs and the generated parts of public/. New projects come with a .gitignore that does this.