Skip to content

Releases

Terminal window
composer install --no-dev --optimize-autoloader --no-interaction
php spark migrate --all
php spark anvil:install --tenant="Muster AG" --email=admin@example.com

anvil:install runs the migrations and anvil:publish (again), creates the first tenant and the administrator and prints a generated password once. The password must be changed at the first login. With an existing account, --promote gives it full access without asking.

A release, in this order:

Terminal window
# 1. Code with the locked dependencies, without dev packages.
# The post-install script of the application runs "spark anvil:publish".
composer install --no-dev --optimize-autoloader --no-interaction
# 2. Database: Shield, Settings, Queue, Anvil and the application.
php spark migrate --all
# 3. Workflow definitions: stores new versions, exit code 1 on errors.
php spark anvil:workflow:check
# 4. Restart the queue worker, so it runs the new code.
sudo systemctl restart anvil-queue
  • anvil:publish copies CSS, JavaScript and fonts to public/assets/anvil and writes manifest.json with the integrity hashes (SRI) the panels use. If your composer.json has no post-install-cmd for it, run php spark anvil:publish yourself; stale assets fail their integrity check in the browser. See Styling.
  • Run anvil:install only once, for the first installation; it creates the first tenant and administrator.
  • Take a database backup before migrate. Do not use migrate:rollback in production; it runs the down() methods of a whole batch.
  • anvil:workflow:check is only needed with workflows.

php spark optimize switches on config and file locator caching in app/Config/Optimize.php (it edits that file), removes the old caches and runs composer install --no-dev. With config caching on, the resolved configuration, including values from .env, is cached under writable/cache/; after every change of a config file or .env run php spark optimize again, or the old values stay active. Try it on staging before you rely on it.

php spark cache:clear empties the cache handler. Rate limit counters and pending single sign-on logins live there, so do not run it as a routine step.

With a release directory per version and a current symlink, the old version keeps serving until the new one is ready:

/var/www/app/
├── releases/
│ ├── 2026-11-01-1030/
│ └── 2026-11-08-0915/
├── shared/
│ ├── .env
│ └── writable/ # cache, logs, session, anvil/files, anvil/exports
└── current -> releases/2026-11-08-0915
  1. Unpack the release to releases/<timestamp>, link .env and writable/ from shared/.
  2. composer install --no-dev … (publishes the assets into the release).
  3. php spark migrate --all and php spark anvil:workflow:check.
  4. Switch the symlink: ln -sfn releases/<timestamp> current.
  5. Reload PHP-FPM (OPcache) and restart the queue worker.

Write migrations so that the old code still works with the new schema (add columns first, remove them in a later release). Keep the last releases for a quick switch back – a switch back of the code does not undo migrations.

Read the upgrade notes and the changelog before updating rakoitde/anvil; new versions may bring migrations, new workflow versions or changed configuration. Update on staging first:

Terminal window
composer update rakoitde/anvil --with-dependencies
php spark migrate --all
php spark anvil:workflow:check
vendor/bin/phpunit