Recipes
A recipe is a production-shaped service definition. It carries the decisions of
the stack it came from: dependency choices, dockerfile targets, a dev override,
a health endpoint, admin tooling, deploy configuration. mx add applies all of
it in one motion.
mx recipes list # what is installedmx recipes info rust-api # options, features, servicesmx add api --recipe rust-api --domain api.localhost # apply itWhat ships
Section titled “What ships”| Recipe | Version | Apply | What it carries |
|---|---|---|---|
astro | 2.0 | ✅ | Astro 5 with Vue 3 islands, SSR, shadcn-vue, PrimeVue, global state, Cloudflare deployment. Brings db and redis. |
laravel | 12.0 | ✅ | Laravel 12 + Octane (Swoole), Filament admin, Inertia.js SSR. Brings a worker, a scheduler, db and redis. |
nuxt | 3.15 | ✅ | Nuxt 3 SSR/SSG with the Nitro server and Tailwind CSS. Standalone. |
rust-api | 1.0 | ✅ | Actix-web + SQLx, hexagonal architecture. Brings db and redis. |
rust-leptos | 1.0 | ✅ | Leptos SSR on Actix-web with shadcn-ui, actor model, Postgres and Redis. |
rust-worker | 1.0 | ✅ | Job worker on Redis pub/sub with Postgres and local LLM evaluation. |
zola | 1.0 | ✅ | Zola static site generator. Single binary, no runtime dependencies. |
A recipe boots unaided
Section titled “A recipe boots unaided”mx new, mx add <svc> --recipe <r>, make dev. No hand edit in between, for
every recipe that brings Postgres with it.
That is new. scripts/init.sh used to copy .env.secrets.template verbatim,
leaving DB_USER, DB_PASSWORD and DB_NAME empty, and Postgres refuses to
initialize with an empty password. scripts/generate-secrets.sh is now the single
generation point every recipe shares: make init runs it, make dev runs
make init, and it fills only what is still empty or still a placeholder. See
Compose & env conventions.
Re-scaffolding: force_init
Section titled “Re-scaffolding: force_init”astro, nuxt and zola run a framework initializer, and by default a second
mx add over a service that already has an app skips it and says so. To start
over from the framework’s own starter:
mx add site --recipe astro --opt force_init=trueThis deletes apps/site/ and re-runs the initializer before mx’s wiring is
layered back on. Destructive by design, and it refuses any target_dir that
escapes the project rather than following it outward.
What mx add actually does
Section titled “What mx add actually does”mx add reads the recipe manifest and works through it in order:
- Options: defaults from the manifest, overridden by
--domainand any--opt key=value.mx recipes info <name>lists what a recipe accepts;rust-api, for example, takesrust,portanddomain. - Placeholders:
{{SERVICE_NAME}}, the port, the domain and the rest are substituted through every template. - Framework scaffold (
init_app, where a recipe declares one):astro,nuxtandzolarun the framework’s own initializer here.mx addprintsScaffolding the app…and then the command it used, orScaffolder skipped: <dir> already holds an appwhen the target is not empty. This step comes first, so mx’s own wiring layers on top of the starter files and wins every collision with them. - Directories: any part of the app’s source tree the scaffolder did not create is filled in.
- Templates: the app files,
docker/compose/<service>.ymland<service>.dev.yml,docker/dockerfiles/<service>/appandapp.prod, anddocker/.config/.env.<service>. - Router labels: the
Host()rule for your--domainand thedevmesh-traefikwiring. - Post-install: anything the recipe declares, such as generating secrets.
Recipes that need backing services also drop db.yml / redis.yml in, once.
A scaffolder command has to be non-interactive, because mx add runs it without a
terminal. The shipped defaults carry the flags that make that true, and a command
that exits 0 while leaving the target empty is treated as a failure rather than
a success, with the command, its working directory and both streams reported. To
use a different starter, pass your own:
mx add site --recipe astro --opt init_cmd='...'.
The corpus has the long-form version of this, including how recipes and the build system fit together:
Writing your own
Section titled “Writing your own”Recipes are directories of templates plus a recipe.json manifest that declares
options, placeholders, directories, templates, an optional init_app command and
optional post-install steps. The full authoring guide (manifest schema,
placeholder rules, the conformance tests a recipe has to pass) is in the corpus:
Also useful while authoring: Docker assembly guide for the dockerfile and compose halves, and Compose & env conventions for what your generated compose files have to honour.
Remote recipes
Section titled “Remote recipes”mx recipes pull, mx recipes versions and mx recipes cache work against
Unyform-hosted blueprints. That path is optional and needs an account; local
recipes need neither. See Remote blueprints.