Skip to content

A tour of your project

manablox create writes a small folder that holds your whole CMS. There is no hidden code in it: the CMS itself comes from npm packages, and your folder only says how to run them. This page walks through every file, so you know which ones matter and which ones you can leave alone.

Most of the time you will touch only three things: the .env file, content-model.ts and, now and then, manablox.config.ts.

A project made with the local preset (Docker runs only the database and the cache, the CMS runs on your computer) with Postgres looks like this:

my-cms/
.env
.env.example
.gitignore
README.md
compose.yml
content-model.ts
manablox.config.ts
manablox.public.config.ts
package.json
pnpm-lock.yaml
pnpm-workspace.yaml
postgres/init/10-public-role.sh
tsconfig.json
node_modules/
data/

manablox.public.config.ts and postgres/init/10-public-role.sh are only there if you answered yes to the public API question (the default). pnpm-lock.yaml and node_modules/ appear once pnpm install has run. data/ appears the first time someone uploads a file.

With SQLite as the database (see The database) there is no postgres/init/ folder, and data/ appears with the first pnpm migrate, because the database itself is the file data/manablox.db.

FileWhat it is forWill you edit it?
.envPasswords, secrets, ports and switches for this one installation. See The .env fileYes, whenever a setting changes
.env.exampleThe same file with the secrets left blank. Safe to share and to commit to GitOnly if you add new variables and want others to know about them
.gitignoreTells Git to leave out node_modules/, data/, .env and log filesRarely
README.mdA short summary of the project and its commands, written for your presetNo, but read it once
compose.ymlTells Docker which helper services to run: Postgres (the database, not with SQLite), Valkey (the cache and job queue) and, if you chose it, Mailpit (a test inbox)Rarely, for example to add Mailpit later
content-model.tsYour content types written as code, plus the plugins. Starts empty. See Content types in codeYes, if you define content types in code
manablox.config.tsThe settings of the CMS process: database, login, uploads, images, mail, logsSometimes, for example for image presets or workflows in code
manablox.public.config.tsThe settings of the public API process your website reads fromRarely
package.jsonThe npm packages the project uses and the short commands (pnpm dev and friends). See Everyday commandsOnly when you update Manablox or add a plugin
pnpm-lock.yamlThe exact package versions that were installed, so every computer gets the same onesNever by hand; pnpm updates it
pnpm-workspace.yamlA list of packages that pnpm may run install scripts for (image processing, password hashing and a few more). Without it pnpm install would skip themNo
tsconfig.jsonSettings for TypeScript, the language the config files are written in. Used by pnpm typecheckNo
postgres/init/10-public-role.shRuns once, the very first time the database starts, and creates a read-only database user for the public API. Only with PostgresNo
node_modules/The installed packagesNever; delete it and run pnpm install if it gets broken
data/Uploaded files and rendered images, and with SQLite the database file. See belowNever by hand

A project made with the docker preset runs everything in containers, which is what you want on a server. It has the same files as above (without data/), plus:

FileWhat it is forWill you edit it?
DockerfileBuilds one image that runs every CMS process. It copies the whole project folder into the image, so plugins in subfolders come alongNo
.dockerignoreKeeps node_modules/, data/, backups/, .env, .git and other local files out of the imageOnly if you add a folder that must not go into the image
compose.ymlHere it describes the whole stack: database (with SQLite a volume instead of a service), cache, a one-time migration step, the CMS, the public API and a web server in frontRarely. The CMS already receives every variable in .env
caddy/CaddyfileThe Caddy web server: HTTPS certificates and which domain goes where. Only with the Caddy proxyRarely
nginx/templates/default.conf.templateThe same job for nginx. Only with the nginx proxyRarely
nginx/certs/ and scripts/selfsigned-certs.shWhere your HTTPS certificate goes, and a script that makes a test certificate. Only with nginx and HTTPSYou put your certificate files there
scripts/lockfile.shWrites pnpm-lock.yaml using Docker, so you do not need Node on the serverNever; run it after changing package.json
scripts/backup.shSaves the database and the uploads into backups/No; see Backups
scripts/restore.shBrings a backup backNo

In a docker project uploads live in a Docker volume instead of the data/ folder, and backups land in a backups/ folder next to compose.yml. Put it on a server walks through that setup.

Your project has up to two CMS processes, and each one reads its own config file:

  • manablox.config.ts is the management instance: the admin in your browser and the API it talks to. pnpm dev starts it.
  • manablox.public.config.ts is the public API: a separate, read-only process that only serves published content to your website. pnpm dev:public starts it. See Management API and public API.

Both files import content-model.ts. That way the admin and the public API always know exactly the same content types and plugins, and you define them in one place only. Both files also read the same .env file.

flowchart LR
  env[".env"] --> mgmt["manablox.config.ts"]
  env --> pub["manablox.public.config.ts"]
  model["content-model.ts"] --> mgmt
  model --> pub
  mgmt --> admin["pnpm dev: admin and management API, port 3000"]
  pub --> api["pnpm dev:public: public API, port 3100"]

A good rule for where a setting belongs:

  • Anything that differs between your computer and the server (passwords, addresses, ports, which mail service) goes into .env. The config files read it from there.
  • Anything that is part of your product and the same everywhere (content types, image presets, workflows in code, plugins) goes into the .ts files.

That way the same files run on your laptop and on the server, and only .env changes.

In a local project the CMS keeps files in data/:

FolderWhat is in it
data/uploads/Every file uploaded in the admin, and the resized images the CMS made from them
data/media-cache-public/Resized images made by the public API, which may not write into the uploads folder
data/media-cache/A cache folder for the CMS process. It usually stays empty, because the CMS keeps its resized images in data/uploads/
data/manablox.dbOnly with SQLite: the database, with manablox.db-wal and manablox.db-shm beside it while the CMS runs

The folders are created on first use. The two cache folders can be deleted at any time; missing images are simply made again on the next request. data/uploads/ is real content: back it up together with the database. Where these folders are is set in .env, see Uploads and images.

With Postgres, your content itself (pages, users, settings) is not in this folder. It lives in the Postgres database, which Docker keeps in a volume. With SQLite it is the file data/manablox.db. The database explains both, Everyday commands how to wipe it, and Backups how to keep it safe.