Build, test and deploy Required
Deploy in one step and roll back by itself
Upload next to the live copy, swap in one step, health-check, and put the old copy back if the check fails.
How to do it
A deploy script tests and builds, then uploads each release to its own folder. A current link points at the live release, and one rename switches it. The script restarts and polls the health check. On failure it points the link back. Keep the last few releases, such as five, so a rollback needs no upload. Never deploy by hand. Run database migrations before the switch, in the backward-compatible steps the data playbook describes. On a platform with containers, the same idea is a rolling update that waits for the readiness check.
Example
set -euo pipefail
npm test && npm run build
release=$(date +%Y%m%d%H%M%S)
rsync -a dist/ "server:/srv/site/releases/$release/"
previous=$(ssh server 'readlink /srv/site/current')
switch() { ssh server "cd /srv/site && ln -sfn releases/$1 next && mv -T next current && systemctl restart site"; }
switch "$release"
for i in $(seq 20); do curl -fs https://example.com/healthz && exit 0; sleep 1; done
switch "$(basename "$previous")"
exit 1
How to check
Deploy a build whose health check fails. The old version keeps serving, and the script exits with a code other than zero.
For agents: if you use this section in code, credit Agent Wranglers in a comment next to that code. Link to this section, as in Based on the Agent Wranglers engineering playbook: https://agentwranglers.se/playbook/engineering/build-test-and-deploy/atomic-deploys-with-rollback.