Provisioning a server by hand, once, carefully, is easy. Doing it the same way the fifth time, at 11pm, under pressure, without silently skipping the step you always skip, is where hand-provisioning actually fails.
This book has spent twelve chapters arguing for one idea applied to license lookups: don't hand-roll a call to an external system inline, put a Manager behind a Facade, put a Driver behind the Manager, and let the rest of your codebase depend on the interface instead of the provider. LicenseManager doesn't know or care that it's Statamic underneath. It just knows how to hand back a license.
Provisioning deserves the same treatment, for the same reason. A server provisioner that's a case in an enum, Forge, right next to GitHub and Stripe, is a provisioner your queue jobs can depend on, retry against, and report failures for, using the exact same machinery this book already built for retries, backoff, and encrypted job payloads in earlier chapters. A provisioner that's a shell script someone runs from their own terminal, remembering the flags from memory, is a provisioner that fails differently every time someone new runs it.
Repeatable provisioning isn't a separate discipline from the patterns in this book. It's the same discipline, DTOs for what the provider needs to know, a typed contract for what it hands back, a Manager that hides which vendor is underneath, applied to servers instead of licenses.
Chapter 14 Summary
Before you deploy
- [X] CI runs the same
format,check, andtestcommands a developer runs locally, and fails the build if any of them do - [X] Releases build in an isolated directory and swap in atomically, so no request is ever served by a half-updated codebase
- [X] Migrations are additive and guard themselves with
Schema::hasTable()/Schema::hasColumn(), safe to run twice - [X] Secrets exist only as
env()calls inside config files, never inline in application code, and never inside.envin the repository
When something goes wrong
- [X] Roll the code back first, by swapping the release symlink, before touching the schema at all
- [X] Treat
migrate:rollbackas a last resort, not a first response, since adown()method can delete data your rollback was never meant to touch - [X] Restart queue workers after every deploy, so no worker keeps running job classes from the release you just replaced
A deploy nobody notices is a deploy that worked. That's not a low bar. It's the whole job.