Hooks
Hooks allow you to run custom scripts at specific points during deployment.
Available hooks
| Hook | Location | Timing |
|---|---|---|
pre-build | Local (CI runner) | Before Docker images are built |
post-build | Local (CI runner) | After Docker images are built |
pre-upload | Server | Before files from uploads entries are copied to the server |
post-upload | Server | After files are uploaded, before stack deployment |
pre-deploy | Server | After file uploads, before stack deployment |
post-deploy | Server | After successful deployment and health checks |
on-failure | Server | After a failed deployment, once rollbacks are done |
When remote_build: true is set, pre-build and post-build hooks run on the server instead of locally — where the build is actually happening.
Local hooks run through bash. On Windows, dockflow automatically uses Git Bash when installed (the System32 WSL bash.exe stub is never used) — install Git for Windows to run local hooks.
Entries
Each phase holds a list of entries, run in the order they are declared. An entry is either a command to run or a script to execute:
# .dockflow/config.yml
hooks:
post-upload:
- name: nginx
run: sudo nginx -t && sudo nginx -s reload
fatal: true
timeout: 30
- script: .dockflow/hooks/warm-cache.sh
- echo "done"| Field | Type | Description |
|---|---|---|
name | string | Label shown in the deploy output. Defaults to the script path, or #1, #2… |
run | string | Inline command |
script | string | Script path, relative to the project root |
fatal | boolean | Abort the deploy if this entry fails. Defaults to hooks.fatal |
timeout | number | Timeout in seconds for this entry. Defaults to hooks.timeout |
An entry needs exactly one of run or script. A bare string is shorthand for run.
Scripts are ordinary files anywhere in the project — .dockflow/hooks/ is a convention, not a
requirement, and a phase can run several of them.
Plugins add entries to these same phases. Theirs run before yours.
Per-entry fatality
hooks.fatal sets the default, and any entry can override it. That lets one critical entry
abort the deploy while its neighbours in the same phase only warn:
hooks:
fatal: false
post-upload:
- name: nginx
run: sudo nginx -t && sudo nginx -s reload
fatal: true # an invalid vhost fails the deploy
- name: notify
run: curl -s https://hooks.example.com/deployedBecause uploads are rolled back when a deploy fails, an aborted post-upload also restores the
previous version of every file it had just uploaded.
timeout works the same way — a config reload wants a few seconds, a database migration may
need the full default of 300.
Reacting to a failed deploy
on-failure runs when a deployment fails, after uploads, images and the stack have been rolled
back — so its entries see the settled state rather than a deploy halfway through undoing itself.
Use it to alert someone or to clean up state your own hooks created.
hooks:
on-failure:
- name: alert
run: >-
curl -s -X POST https://hooks.example.com/alert
--data-urlencode "text=Deploy {{ version }} to {{ env }} failed: $DOCKFLOW_ERROR"Two variables describe what happened:
| Variable | Value |
|---|---|
DOCKFLOW_ERROR | The error that failed the deployment |
DOCKFLOW_ROLLED_BACK_TO | The release the stack was rolled back to, or empty if none |
on-failure entries never abort anything, whatever fatal says — the deploy has already
failed, and a hook that threw would bury the error that caused it. A failing entry only prints
a warning.
Templating
Hooks are rendered with Nunjucks before execution. You can use any template variable:
#!/bin/bash
echo "Deploying {{ config.project_name }} version {{ version }} to {{ env }}"
# Access server environment variables
DATABASE_URL="{{ current.env.database_url }}"Examples
Pre-build: Generate assets
# .dockflow/config.yml
hooks:
pre-build:
- npm run build:assetsPost-build: Security scan
# .dockflow/config.yml
hooks:
post-build:
- docker scan {{ project_name }}:{{ version }} || truePre-upload: Stop a service before files arrive
# .dockflow/config.yml
hooks:
pre-upload:
- sudo systemctl stop myapp || truePost-upload: Run a migration on uploaded files
# .dockflow/config.yml
hooks:
post-upload:
- cd /var/www/myapp && php artisan migrate --forcePre-deploy: Database backup
A longer step reads better as a script. Its path is declared in config.yml; the file
itself is rendered like any other file under .dockflow/:
# .dockflow/config.yml
hooks:
pre-deploy:
- name: backup
script: .dockflow/hooks/backup.sh
fatal: true# .dockflow/hooks/backup.sh
#!/bin/bash
set -euo pipefail
pg_dump "{{ current.env.database_url }}" > /backups/pre-deploy-{{ version }}.sqlPost-deploy: Reload a systemd service
# .dockflow/config.yml
hooks:
post-deploy:
- sudo systemctl daemon-reload
- sudo systemctl restart rclone-s3.serviceSeveral entries in one phase
A phase runs its entries in order, commands and scripts alike:
# .dockflow/config.yml
hooks:
pre-build:
- script: .dockflow/hooks/check-env.sh
- script: scripts/generate-assets.sh
- npm run lintPost-deploy: Notify team
# .dockflow/config.yml
hooks:
post-deploy:
- script: .dockflow/hooks/notify.sh# .dockflow/hooks/notify.sh
#!/bin/bash
curl -X POST "https://hooks.slack.com/services/xxx" \
-H "Content-Type: application/json" \
-d '{"text":"Deployed {{ project_name }} {{ version }} to {{ env }}"}'Configuration
# .dockflow/config.yml
hooks:
enabled: true # Enable/disable all hooks (default: true)
timeout: 300 # Default timeout per entry, in seconds (default: 300)
fatal: false # Default fatality per entry (default: false)
pre-build:
- echo "starting build"
post-deploy:
- sudo systemctl daemon-reload
- name: restart
run: sudo systemctl restart myservice
fatal: true| Field | Type | Description | Default |
|---|---|---|---|
enabled | boolean | Enable or disable all hooks | true |
timeout | number | Default timeout per entry, in seconds | 300 |
fatal | boolean | Default fatality per entry | false |
pre-build | entry[] | Entries to run before building images | — |
post-build | entry[] | Entries to run after building images | — |
pre-upload | entry[] | Entries to run on the server before files are uploaded | — |
post-upload | entry[] | Entries to run on the server after files are uploaded | — |
pre-deploy | entry[] | Entries to run on the server before the stack is deployed | — |
post-deploy | entry[] | Entries to run on the server after a successful deployment | — |
on-failure | entry[] | Entries to run on the server after a failed deployment, never fatal | — |
See Entries for the fields an entry accepts.
With the default fatal: false, a failing hook does not abort the deploy. If an entry runs
a critical operation — a migration, a config reload — set fatal: true on that entry.