Skip to Content
⚠️ Dockflow is currently under development. Bugs may occur. Please report any issues on GitHub.

Hooks

Hooks allow you to run custom scripts at specific points during deployment.

Available hooks

HookLocationTiming
pre-buildLocal (CI runner)Before Docker images are built
post-buildLocal (CI runner)After Docker images are built
pre-uploadServerBefore files from uploads entries are copied to the server
post-uploadServerAfter files are uploaded, before stack deployment
pre-deployServerAfter file uploads, before stack deployment
post-deployServerAfter successful deployment and health checks
on-failureServerAfter 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"
FieldTypeDescription
namestringLabel shown in the deploy output. Defaults to the script path, or #1, #2
runstringInline command
scriptstringScript path, relative to the project root
fatalbooleanAbort the deploy if this entry fails. Defaults to hooks.fatal
timeoutnumberTimeout 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/deployed

Because 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:

VariableValue
DOCKFLOW_ERRORThe error that failed the deployment
DOCKFLOW_ROLLED_BACK_TOThe 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:assets

Post-build: Security scan

# .dockflow/config.yml hooks: post-build: - docker scan {{ project_name }}:{{ version }} || true

Pre-upload: Stop a service before files arrive

# .dockflow/config.yml hooks: pre-upload: - sudo systemctl stop myapp || true

Post-upload: Run a migration on uploaded files

# .dockflow/config.yml hooks: post-upload: - cd /var/www/myapp && php artisan migrate --force

Pre-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 }}.sql

Post-deploy: Reload a systemd service

# .dockflow/config.yml hooks: post-deploy: - sudo systemctl daemon-reload - sudo systemctl restart rclone-s3.service

Several 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 lint

Post-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
FieldTypeDescriptionDefault
enabledbooleanEnable or disable all hookstrue
timeoutnumberDefault timeout per entry, in seconds300
fatalbooleanDefault fatality per entryfalse
pre-buildentry[]Entries to run before building images
post-buildentry[]Entries to run after building images
pre-uploadentry[]Entries to run on the server before files are uploaded
post-uploadentry[]Entries to run on the server after files are uploaded
pre-deployentry[]Entries to run on the server before the stack is deployed
post-deployentry[]Entries to run on the server after a successful deployment
on-failureentry[]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.