Features / Extend

Runtime configuration

Frontend URLs, branding, feature flags and plugin settings live in one JSON5 file, editable through the admin UI, the API or the CLI. Hot reload in 300 ms, every change versioned, rollback with one click.

Configuration in the admin UI: frontend URLs and branding per space, applied without a restart
Configuration in the admin UI: frontend URLs and branding per space, applied without a restart

The frontend URL changes, a feature flag needs to go live, the logo gets swapped — and until now that meant touching an env var, rebuilding the container, restarting. RustyCMS separates operational settings from bootstrap secrets. Whatever changes during normal operation lives in _config/admin.json5 and takes effect without a restart. Whatever is secret — session secret, API keys, database URL — stays an env var and never touches disk.

Three ways in, one file

The admin UI renders a form at /admin/settings from the schema the server exposes at /api/config/_schema. Fields that only apply after a restart are marked as such. The same configuration is read and written via GET/PUT /api/config/admin, and for scripts and CI there is the CLI:

admin-config --content-dir ./content show
admin-config --content-dir ./content get frontend.site-a.baseUrl
admin-config --content-dir ./content set frontend.site-a.baseUrl '"https://www.example.com"'
admin-config --content-dir ./content validate

All three write through the same atomic path — temp file plus rename, no half-written state. A public subset is served at /api/config/public without login so the login page and the frontend can pick up branding and URLs; flags prefixed with _private. are stripped from it.

Changed on disk, live in the process

A file watcher observes _config/ and reloads the file within about 300 ms — whether it was changed by rsync, an editor or a deploy script. The hot reload only re-reads the file; it cannot escalate privileges or execute code.

Every change has a history

Before every save, the previous state is snapshotted to _config/.history/<timestamp>-by-<actor>.json5; the newest 50 are kept. In the admin UI a sidebar lists the snapshots: click one to preview it, “Roll back” restores it — and snapshots the current state first. The API offers the same through /api/config/history and /api/config/history/<id>.

Plugins bring their own section

A plugin registers a schema for its settings at boot and automatically appears as its own section in the form. Values are stored under plugins.<id> in the same file — no second configuration mechanism, no separate endpoint per plugin.

What stays an env var

Store mode, port, cache TTL, rate limits, backup directory: everything the process needs in order to start remains an env var or CLI flag. rustycms --help lists every variable with its default. Existing deployments that still set the preview configuration as an env var keep working: on the first start without admin.json5 it is picked up, and admin-config import-env writes it into the file in one step.

Want to see this on your own project?

Tell me briefly what you're planning. I'll show the admin UI on a real installation and say honestly whether it fits.

Request early access