> ## Documentation Index
> Fetch the complete documentation index at: https://developer.upsun.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Comparison of hooks

> What hooks are available in the build and deploy process and how to choose which to use.

The following table presents the main differences among the three available hooks:

| Hook name     | Failures stop build | Variables available | Services available | Timeout | Run on `worker` instances | Writable directories                                   | Blocks requests | Runs on all redeploys\* |
| ------------- | ------------------- | ------------------- | ------------------ | ------- | ------------------------- | ------------------------------------------------------ | --------------- | ----------------------- |
| `build`       | Yes                 | Build variables     | No                 | 1 hour  | Yes                       | `$PLATFORM_APP_DIR`, `$PLATFORM_CACHE_DIR`, and `/tmp` | No              | No                      |
| `deploy`      | No                  | Runtime variables   | Yes                | None    | No                        | [Mounts](/docs/configure-apps/image-properties/mounts) | Yes             | No                      |
| `post_deploy` | No                  | Runtime variables   | Yes                | None    | No                        | [Mounts](/docs/configure-apps/image-properties/mounts) | No              | Yes                     |

\* All of the hooks run with changes to the code or environment.
This column indicates which hooks run on a redeploy without any code changes.

## Build hook

The `build` hook is run after any [build flavor](/docs/configure-apps/app-reference/single-runtime-image#build).
During this hook, no services (such as a database) or any persistent file mounts are available
as the application hasn't yet been deployed.

The `build` hook can access only the variables that are available at build time:

* Variables provided by Upsun, as listed in [this table](/docs/development/variables/use-variables#use-provided-variables) (see the **Build** column)
* User-defined project-level or environment-specific build-time variables (**Available during buildtime** is set in the console or the `--visible-build=true` option was set by using the CLI)

During the `build` hook, there are three writeable directories:

* `$PLATFORM_APP_DIR`:
  This is where your code is checked out and is the working directory when the `build` hook starts.
  The contents of this directory after the build hook is the application that gets deployed.
* `$PLATFORM_CACHE_DIR`:
  This directory persists between builds, but isn't deployed as part of your application.
  It's a good place for temporary build artifacts that can be reused between builds.
  It's shared by all builds on all branches.
* `/tmp`:
  The temp directory is also useful for writing files that aren't needed in the final application,
  but it's wiped between each build.
  Note that `$PLATFORM_CACHE_DIR` is mapped to `/tmp`
  and together they offer about 8 GB of free space.

The only constraint on what can be downloaded during a `build` hook is the disk space available for builds.

This is *not* the disk specified by your [resources configuration](/docs/manage-resources).

If you exceed this limit, you receive a `No space left on device` error.
See how to [troubleshoot this error](/docs/troubleshooting/disks#no-space-left-on-device).

The `build` hook runs only when the app or its runtime (variables and such) have changed.
Redeploys with no changes trigger only the `post_deploy` hook.
If you need the `build` hook to run, [manually trigger a build](/docs/troubleshooting/general#manually-trigger-builds).

Each hook is executed as a single script, so they're considered to have failed only if the final command in them fails.
To cause them to fail on the first failed command, add `set -e` to the beginning of the hook.
If a `build` hook fails for any reason, the build is aborted and the deploy doesn't happen.
Note that this only works for `build` hooks.
If other hooks fail, the deploy still happens.

### Timeout

Build hooks automatically time out if they run for 1 hour.
So if you accidentally add an unbroken loop, it gets cut off and you can continue with other activities.

## Deploy hook

The `deploy` hook is run after the app container has been started but before it has started accepting requests.
Note that the deploy hook only runs on [`web` instances](/docs/configure-apps/image-properties/mounts),
not [`worker` instances](/docs/configure-apps/image-properties/mounts).

You can access other services at this stage (such as MySQL, Solr, Redis).
The disk where the application lives is read-only at this point.

This hook should be used when something needs to run once when new code is deployed.
It isn't run when a host is restarted (such as during region maintenance),
so anything that needs to run each time an instance of an app starts (regardless of whether there's new code)
should go in the `pre_start` key in [your `web` configuration](/docs/configure-apps/image-properties/web#web-commands).
For example, clearing the cache.

Be aware: The deploy hook blocks the site accepting new requests.
If your `deploy` hook is only a few seconds,
incoming requests in that time are paused and continue when the hook is finished.
So it effectively appears as if the site just took a few extra seconds to respond.
If the hook takes too long, requests can't be held and appear as dropped connections.
Only run tasks in your deploy hook that have to be run exclusively,
such as database schema updates or some types of cache clear (those where the code must match what's on the disk).
A task that can safely run concurrently with new incoming requests should be run as a `post_deploy` hook instead.

After a Git push, in addition to the log shown in the activity log,
the execution of the `deploy` hook is logged in the [deploy log](/docs/observability/logs/access-logs#container-logs).
For example:

```bash theme={null}
[2026-03-01 08:27:25.495579] Launching command 'bash export-config.sh'.

🔥 Successfully cleared configuration
🚀 Added new configuration details
```

Your `deploy` hook is tied to commits in the same way as your builds.
Once a commit has been pushed and a new build image has been created,
the result of both the `build` and `deploy` hooks are reused until there is a new git commit.
Redeploys with no changes trigger only the `post_deploy` hook.
If you need the `deploy` hook to run, [manually trigger a build](/docs/troubleshooting/general#manually-trigger-builds).

## Post-deploy hook

The `post_deploy` hook functions exactly the same as the `deploy` hook,
but after the container is accepting connections.
It runs concurrently with normal incoming traffic.
That makes it well suited to any updates that don't require exclusive database access.

What's "safe" to run in a `post_deploy` hook vs. in a `deploy` hook varies by the application.
Often times content imports, some types of cache warmups, and other such tasks are good candidates for a `post_deploy` hook.

In addition to the activity log, the `post_deploy` hook logs to the [post-deploy log](/docs/observability/logs/access-logs#container-logs).

The `post_deploy` hook is the only hook that runs during a redeploy. **Make sure the scripts in your `post_deploy` hook are written to be idempotent** (safe to run multiple times) or have checks against duplication.
