> ## 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.

# Build and deploy

> See how applications get built and deployed with Upsun Cloud.

export const SettingsIcon = () => <svg width="24px" height="24px" style={{
  display: 'inline',
  verticalAlign: 'middle'
}}>
    <title id="settings-icon">Settings</title>
    <path d="M10.5289 21.9416C9.86066 21.8582 9.3595 21.3576 9.19245 20.6903L9.02539 19.6892C8.85834 19.6058 8.77482 19.6058 8.60776 19.5224L7.93955 20.0229C7.43839 20.44 6.68665 20.44 6.10196 20.0229C6.10196 20.0229 4.09732 18.1042 4.01379 17.9374C3.51263 17.3535 3.51263 16.6027 3.93027 16.0187L4.51495 15.3514C4.43143 15.1845 4.43143 15.1011 4.3479 14.9343L3.42911 14.7674C2.76089 14.684 2.25973 14.1835 2.09268 13.4327C2.00915 13.1824 2.09268 10.4296 2.09268 10.4296C2.17621 9.76222 2.67737 9.2617 3.34558 9.09486L4.3479 8.92802C4.43143 8.8446 4.43143 8.76118 4.51495 8.59434L4.01379 7.92697C3.59616 7.42645 3.59616 6.67567 4.01379 6.09173C4.01379 6.09173 5.93491 4.08964 6.10196 4.00622C6.68665 3.5057 7.43839 3.5057 8.02307 3.9228L8.69129 4.50675C8.85834 4.42333 8.94187 4.42333 9.10892 4.33991L9.27597 3.42228C9.3595 2.75492 9.86066 2.2544 10.6124 2.08756C10.863 2.00414 13.2853 2.00414 13.5358 2.08756H13.6194C14.2876 2.17098 14.7887 2.6715 14.9558 3.33886L15.1228 4.33991C15.2064 4.42333 15.2899 4.50675 15.457 4.50675L16.1252 4.00622C16.6263 3.58912 17.3781 3.58912 17.9628 4.00622C17.9628 4.00622 19.9674 5.92489 20.0509 6.09173C20.5521 6.67567 20.5521 7.42645 20.1344 8.0104L19.6333 8.67776C19.7168 8.8446 19.7168 9.01144 19.8003 9.09486L20.7191 9.2617C21.3873 9.34512 21.972 9.92906 22.0556 10.5964V13.5996C21.972 14.2669 21.4709 14.7674 20.8027 14.9343L19.8003 15.1011C19.7168 15.268 19.7168 15.3514 19.6333 15.5182L20.218 16.269C20.6356 16.7695 20.6356 17.5203 20.218 18.1042L18.0463 20.2732C17.4616 20.6903 16.7099 20.6903 16.2087 20.2732L15.3734 19.6058C15.2064 19.6892 15.1228 19.6892 14.9558 19.7726L14.7887 20.6903C14.7052 21.3576 14.1205 21.9416 13.4523 22.025H10.5289V21.9416ZM11.5312 20.3566C11.8653 20.3566 12.1994 20.3566 12.45 20.3566C12.8676 20.3566 13.2017 20.0229 13.2853 19.6058L13.3688 18.9384C13.3688 18.6882 13.6194 18.4379 13.8699 18.2711L15.1228 17.7706C15.3734 17.6871 15.7075 17.6871 15.9581 17.854L16.5428 18.2711C16.8769 18.5213 17.3781 18.5213 17.6286 18.1877C17.7957 18.0208 18.0463 17.7706 18.2969 17.5203C18.5474 17.1866 18.631 16.7695 18.3804 16.4358L17.8792 16.0187C17.7122 15.7685 17.6286 15.4348 17.7957 15.1845L18.2969 14.0167C18.3804 13.7664 18.631 13.5996 18.9651 13.5161L19.6333 13.4327C20.0509 13.3493 20.385 13.0156 20.385 12.5985C20.385 12.2648 20.385 11.9311 20.385 11.6809C20.385 11.2638 20.0509 10.9301 19.6333 10.8467L18.9651 10.7633C18.7145 10.7633 18.4639 10.513 18.2969 10.2627L17.7957 9.01144C17.7122 8.76118 17.7122 8.4275 17.8792 8.17724L18.2969 7.59329C18.5474 7.25961 18.5474 6.84251 18.2133 6.50883C18.0463 6.34199 17.7957 6.09173 17.5451 5.84147C17.211 5.50779 16.7934 5.50779 16.4593 5.75805L16.0416 6.17515C15.7911 6.34199 15.457 6.42541 15.2064 6.25857L14.037 5.75805C13.7864 5.67463 13.6194 5.42437 13.5358 5.09069L13.3688 4.50675C13.2853 4.08964 12.9511 3.75596 12.5335 3.75596C12.1994 3.75596 11.8653 3.75596 11.6147 3.75596C11.1971 3.75596 10.863 4.08964 10.7795 4.50675L10.6959 5.17411C10.6959 5.42437 10.4453 5.67463 10.1948 5.84147L9.02539 6.25857C8.69129 6.42541 8.44071 6.34199 8.19013 6.17515L7.60544 5.75805C7.27133 5.50779 6.77017 5.50779 6.51959 5.84147C6.26901 6.00831 6.10196 6.25857 5.85138 6.42541C5.6008 6.75909 5.51727 7.17619 5.85138 7.50987L6.18549 8.09382C6.35254 8.34408 6.43607 8.67776 6.26901 8.92802L5.76785 10.0959C5.68433 10.3462 5.43375 10.513 5.09964 10.5964L4.43143 10.6798C4.01379 10.7633 3.67969 11.0969 3.67969 11.514C3.67969 11.8477 3.67969 12.1814 3.67969 12.4317C3.67969 12.8488 4.01379 13.1825 4.43143 13.2659L5.09964 13.3493C5.35022 13.3493 5.6008 13.5996 5.76785 13.8498L6.26901 15.1011C6.35254 15.3514 6.35254 15.6851 6.18549 15.9353L5.76785 16.5193C5.51727 16.8529 5.51727 17.3535 5.85138 17.6037C6.01843 17.7706 6.26901 18.0208 6.51959 18.2711C6.8537 18.5213 7.27133 18.6048 7.60544 18.3545L8.02307 17.854C8.27365 17.6871 8.60776 17.6037 8.85834 17.7706L10.0277 18.2711C10.2783 18.3545 10.4453 18.6048 10.5289 18.9384L10.6124 19.6058C10.7795 20.0229 11.1136 20.3566 11.5312 20.3566ZM18.798 6.92593C18.798 6.92593 18.798 7.00935 18.798 6.92593V6.92593Z"></path>
    <path d="M12.0324 17.0198C9.27597 17.0198 7.02075 14.7675 7.02075 12.0146C7.02075 9.26172 9.27597 7.00937 12.0324 7.00937C14.7887 7.00937 17.044 9.26172 17.044 12.0146C17.044 14.7675 14.7887 17.0198 12.0324 17.0198ZM12.0324 8.67777C10.1948 8.67777 8.69129 10.1793 8.69129 12.0146C8.69129 13.8498 10.1948 15.3514 12.0324 15.3514C13.8699 15.3514 15.3734 13.8498 15.3734 12.0146C15.3734 10.1793 13.8699 8.67777 12.0324 8.67777Z"></path>
  </svg>;

export const ChevronIcon = () => <svg width="24px" height="24px" style={{
  display: 'inline',
  verticalAlign: 'middle'
}}>
    <title id="chevron-icon">Chevron Icon</title>
    <path d="M6.90002 9.8999C6.90002 9.5999 7.00002 9.3999 7.20002 9.1999C7.60002 8.7999 8.20002 8.7999 8.60002 9.1999L12.1 12.6999L15.6 9.1999C16 8.7999 16.6 8.7999 17 9.1999C17.4 9.5999 17.4 10.1999 17 10.5999L12.8 14.7999C12.4 15.1999 11.8 15.1999 11.4 14.7999L7.20002 10.5999C7.00002 10.3999 6.90002 10.1999 6.90002 9.8999Z" fill="current"></path>
  </svg>;

Each time you push a change to your app through Git or activate an [environment](/docs/environments),
your app goes through a process to be built and deployed.
If your app is redeployed with no changes to its codebase, the output of the previous build and deploy process is reused.

The build process looks through the configuration files in your repository and assembles the necessary containers.
The deploy process makes those containers live, replacing any previous versions, with minimal interruption in service.

<div className="block dark:hidden">
  ```mermaid theme={null}
  ---
  config:
    theme: base
    themeVariables:
      primaryColor: '#F7F8F8'
      primaryTextColor: '#0E1113'
      primaryBorderColor: '#6046FF'
      lineColor: '#6046FF'
      secondaryColor: '#F7F8F8'
      tertiaryColor: '#F7F8F8'
      background: 'transparent'
      mainBkg: '#F7F8F8'
      nodeBorder: '#6046FF'
      nodeTextColor: '#0E1113'
      clusterBkg: '#FFFFFF'
      clusterBorder: '#6046FF'
      titleColor: '#0E1113'
      edgeLabelBackground: 'transparent'
      transitionColor: '#6046FF'
    look: neo
    fontSize: 18
  ---
  stateDiagram
    direction LR
    state Build {
      direction TB
      GitPush --> ValidateConfig
      ValidateConfig --> PullImage
      PullImage --> InstallDeps
      InstallDeps --> BuildFlavor
      BuildFlavor --> BuildHook
      BuildHook --> FreezeContainer
      GitPush
      ValidateConfig
      PullImage
      InstallDeps
      BuildFlavor
      BuildHook
      FreezeContainer
    }
    state Deploy {
      direction TB
      HoldRequests --> UnmountContainers
      UnmountContainers --> MountFS
      MountFS --> ExposeServices
      ExposeServices --> StartCommand
      StartCommand --> DeployHook
      DeployHook --> ServeRequests
      HoldRequests
      UnmountContainers
      MountFS
      ExposeServices
      StartCommand
      DeployHook
      ServeRequests
    }
    Build --> Deploy
    Build:BUILD PHASE
    GitPush:Git push or activation
    ValidateConfig:Validate configuration
    PullImage:Pull container image
    InstallDeps:Install dependencies
    BuildFlavor:Run build flavor commands
    BuildHook:Run build hook
    FreezeContainer:Freeze app container
    Deploy:DEPLOY PHASE
    HoldRequests:Hold requests
    UnmountContainers:Unmount current containers
    MountFS:Mount file systems
    ExposeServices:Expose services
    StartCommand:Run start command
    DeployHook:Run deploy hook
    ServeRequests:Serve requests

    style Build fill:#FFFFFF,stroke:#6046FF
    style Deploy fill:#FFFFFF,stroke:#6046FF
  ```
</div>

<div className="hidden dark:block">
  ```mermaid theme={null}
  ---
  config:
    theme: base
    themeVariables:
      primaryColor: '#2B3134'
      primaryTextColor: '#FFFFFF'
      primaryBorderColor: '#BFB5FF'
      lineColor: '#BFB5FF'
      secondaryColor: '#2B3134'
      tertiaryColor: '#2B3134'
      background: 'transparent'
      mainBkg: '#2B3134'
      nodeBorder: '#BFB5FF'
      nodeTextColor: '#FFFFFF'
      clusterBkg: '#191C1E'
      clusterBorder: '#BFB5FF'
      titleColor: '#BFB5FF'
      edgeLabelBackground: 'transparent'
      transitionColor: '#BFB5FF'
    look: neo
    fontSize: 18
  ---
  stateDiagram
    direction LR
    state Build {
      direction TB
      GitPush --> ValidateConfig
      ValidateConfig --> PullImage
      PullImage --> InstallDeps
      InstallDeps --> BuildFlavor
      BuildFlavor --> BuildHook
      BuildHook --> FreezeContainer
      GitPush
      ValidateConfig
      PullImage
      InstallDeps
      BuildFlavor
      BuildHook
      FreezeContainer
    }
    state Deploy {
      direction TB
      HoldRequests --> UnmountContainers
      UnmountContainers --> MountFS
      MountFS --> ExposeServices
      ExposeServices --> StartCommand
      StartCommand --> DeployHook
      DeployHook --> ServeRequests
      HoldRequests
      UnmountContainers
      MountFS
      ExposeServices
      StartCommand
      DeployHook
      ServeRequests
    }
    Build --> Deploy
    Build:BUILD PHASE
    GitPush:Git push or activation
    ValidateConfig:Validate configuration
    PullImage:Pull container image
    InstallDeps:Install dependencies
    BuildFlavor:Run build flavor commands
    BuildHook:Run build hook
    FreezeContainer:Freeze app container
    Deploy:DEPLOY PHASE
    HoldRequests:Hold requests
    UnmountContainers:Unmount current containers
    MountFS:Mount file systems
    ExposeServices:Expose services
    StartCommand:Run start command
    DeployHook:Run deploy hook
    ServeRequests:Serve requests

    style Build fill:#191C1E,stroke:#BFB5FF
    style Deploy fill:#191C1E,stroke:#BFB5FF
  ```
</div>

Hooks are points in the build and deploy process where you can inject a custom script.

## The build

The outcome of the build process is designed to be repeatable and reusable.
Each app in a project is built separately.

Container configuration depends exclusively on your configuration files.
So each container is tied to a specific Git commit.
If there are no new changes for a given container, the existing container can be reused.
This saves you the time the build step would take.

This means the build is independent of the given environment and preview environments are perfect copies of production.
If you use environment variables to set up different build configuration options for different environments,
your build step isn't reused and your preview environments may differ from production.

You can't connect to services (like databases) during the build step.
Once the app has gone through all of the build steps, it can connect to services in the deploy process.

### Build steps

<Steps>
  <Step title="Validate configuration">
    The configuration is checked by validating the `.upsun/` directory and scanning the repository for any app configuration to validate.
  </Step>

  <Step title="Pull container images">
    Any container images that have been built before and that don't have any changes are pulled to be reused.
  </Step>

  <Step title="Install dependencies">
    If you have specified additional global dependencies, they're downloaded during this step.
    This is useful for commands you may need in the build hook.
  </Step>

  <Step title="Run build flavor commands">
    For some languages (NodeJS, PHP), a series of standard commands are run based on the build flavor.
    You can change the flavor or skip the commands by specifying it in your `.upsun/config.yaml` file.
  </Step>

  <Step title="Run build hook">
    The `build` hook comprises one or more shell commands that you write to finish creating your production code base: for example, compiling Sass files, running a bundler, rearranging files on disk, or compiling.
    The committed build hook runs in the build container.
    During this time, commands have write access to the file system, but there aren't connections to other containers (services and other apps).

    For automated builds, you can use the [`CI` environment variable](/docs/development/variables/use-variables#use-provided-variables) in build scripts and tooling to modify build behavior (for example, to disable attempts to connect to other containers during the build phase, or to disable interactivity). These modifications can help to prevent build failures.

    You can also manually [cancel deployments stuck on the build hook](/docs/environments/cancel-activity).
  </Step>

  <Step title="Freeze app container">
    The file system is frozen and produces a read-only container image, which is the final build artifact.
  </Step>
</Steps>

## The deploy

The deploy process connects each container from the build process and any services.
The connections are defined in your app and services configuration.

So unlike the build process, you can now access other containers,
but the file system is read-only.

### Deploy steps

<Steps>
  <Step title="Hold requests">
    Incoming [idempotent requests](https://www.iana.org/assignments/http-methods/http-methods.xhtml) (like `GET`, `PUT`, `DELETE` but **not** `POST`, `PATCH` etc.) are held.
  </Step>

  <Step title="Unmount current containers">
    Any previous containers are disconnected from their file system mounts.
  </Step>

  <Step title="Mount file systems">
    The file system is connected to the new containers.
    New branches have file systems cloned from their parent.
  </Step>

  <Step title="Expose services">
    Networking connections are opened between any containers specified in your app and services configurations.
  </Step>

  <Step title="Run (pre-) start commands">
    The [commands](/docs/configure-apps/image-properties/web#web-commands) necessary to start your app are run.
    Often this stage will only include a start command, which is restarted if ever terminated going forward.
    You may also, however, define a `pre_start` command, when you need to run *per-instance* actions.
    In this case, as you might expect, the `pre_start` command is run, then the `start` command.
  </Step>

  <Step title="Run deploy hook">
    The `deploy` hook is any number of shell commands you can run to finish your deployment.
    This can include clearing caches, running database migrations, and setting configuration that requires relationship information.
  </Step>

  <Step title="Serve requests">
    Incoming requests to your newly deployed application are allowed.
  </Step>
</Steps>

After the deploy process is over, any commands in your `post_deploy` hook are run.

## Deployment types

Upsun Cloud supports two deployment types - automatic and manual. These types help to provide control over when changes are applied to development, staging and production environments.

### Automatic deployment (default)

This is the default behavior for all environments. With automatic deployment, changes like code pushes and variable updates are deployed immediately. This type of deployment is best suited for rapid iteration during development.

### Manual deployment

You can deploy applications manually in any environment type (development/preview, staging, and production). When [enabled](#change-deployment-type), manual deployment lets you control when deployments happen: changes are staged but not deployed until you explicitly trigger a deployment. Manual deployment is ideal for teams that want to bundle multiple changes and deploy them together in a controlled manner.

When manual deployment is enabled in an environment, the following actions are queued until deployment is triggered:

| Category | Staged Activities |
| - | - |
| **Code** | `environment.push`, `environment.merge`, `environment.merge-pr` |
| **Variables** | `environment.variable.create`, `update`, `delete` |
| **Resources** | `environment.resources.update` |
| **Domains & Routes** | `environment.domain.*`, `environment.route.*` |
| **Subscription** | `environment.subscription.update ` |
| **Environment Settings** | `environment.update.http_access`, `smtp`, `restrict_robots` |

<Info>
  To restart your application without applying staged changes, run `upsun redeploy` or click **Redeploy** in the Console.
</Info>

### Change deployment type

You can adjust deployment behavior in your environment.

<Tabs>
  <Tab title="Using the CLI">
    Use the following command in the CLI to view or change the deployment type:

    ```bash theme={null}
    upsun environment:deploy:type
    ```

    The output should look similar to the example below:

    ```bash theme={null}
    Selected project: [my-project (ID)]
    Selected environment: main (type: production)
    Deployment type: manual
    ```
  </Tab>

  <Tab title="Using the Console">
    To switch to manual, navigate to the environment settings in the Console and select the manual deployments option.
  </Tab>
</Tabs>

### Trigger deployment manually

Once manual deployment is enabled, eligible changes are staged. You can deploy them in the following ways:

<Tabs>
  <Tab title="Using the CLI">
    Deploy staged changes to your chosen environment using the following command:

    ```bash theme={null}
    upsun environment:deploy
    ```

    The output should look similar to the example below:

    ```bash theme={null}
    Deploying staged changes:
    +---------------+---------------------------+-----------------------------------------------------------+---------+
    | ID            | Created                   | Description                                               | Result  |
    +---------------+---------------------------+-----------------------------------------------------------+---------+
    | 5uh3xwmkh5boq | 2026-01-01T14:01:10+00:00 | Patrick pushed to main                                    | failure |
    | fno2qiodq7e3c | 2026-01-01T13:06:18+00:00 | Arseni updated resource allocation on main                | success |
    | xzvcazrtoafeu | 2026-01-01T13:01:10+00:00 | Pilar added variable HELLO_WORLD to main                  | success |
    | fq73u53ruwloq | 2026-01-01T12:06:17+00:00 | Pilar pushed to main                                      | success |
    +---------------+---------------------------+-----------------------------------------------------------+---------+
    ```
  </Tab>

  <Tab title="Using the Console">
    In the Console, a deploy button will be visible in the environment whenever changes are staged. Click this button to deploy your staged changes.
  </Tab>

  <Tab title="Using the API">
    Trigger the deployment of staged changes with the following:

    ```bash theme={null}
    POST /projects/{projectId}/environments/{environmentId}/deploy
    ```
  </Tab>
</Tabs>

<Tip>
  As soon as your deployment type is switched from manual to automatic, all currently staged changes are deployed immediately and the environment resumes its default automatic deployment behavior.
</Tip>

## Maintenance window

A maintenance window is a recurring time slot when Upsun Cloud applies patch updates to your services' container images, such as bug and security fixes, keeping them up to date on a predictable schedule.

Some of these updates can cause brief downtime. Instead of Upsun Cloud running them at any time, you choose when they happen (for example, at a time that works best for your application and users). You set how often the window repeats (every 2 or 4 weeks), the day, and the time.

You configure one maintenance window per project. Upsun Cloud may still apply urgent or critical fixes outside of the project's maintenance window.

### Maintenance windows and zero-downtime deployments

[Zero-downtime deployments](#zero-downtime-deployments) use a rolling strategy, which keeps your app running on a temporary copy while the original updates. Some platform updates can't be applied that way, such as a restart of a database service onto a new version. A maintenance window gives those updates a scheduled time to run, so your regular deployments can stay zero-downtime.

Without a maintenance window, rolling deployments aren't available: requesting one is rejected until a project admin sets a maintenance window. Deployments that don't request the rolling strategy are unaffected and continue to use the default stop-start strategy.

Rolling deployments also [aren't available for projects that use Varnish](#zero-downtime-deployments), regardless of whether a maintenance window is set.

Maintenance windows run only against active environments; [paused or inactive environments](/docs/environments/deactivate-environment) are skipped, even if the project has a maintenance window configured.

### What happens during a maintenance window

During your scheduled maintenance window, Upsun Cloud redeploys your environment to apply any pending patch updates to your services' container images, which can cause brief downtime.

Maintenance redeployments and your regular deployments stay separate: a maintenance redeployment skips your own staged or pending activities, and a regular deployment doesn't apply pending patch updates. A code push won't unexpectedly restart a service onto a new version, except for urgent or critical fixes, which Upsun Cloud may still apply outside of the maintenance window.

After the redeployment on your production environment succeeds, Upsun Cloud schedules the same redeployment on your non-production environments, staggered roughly 15 minutes apart so they don't all redeploy at once.

If no updates are pending, nothing runs.

### Configure a maintenance window

A project's maintenance window is not enabled by default.

<Warning>
  Once enabled, a maintenance window can't be turned off from the Console or CLI. [Contact support](/docs/core-concepts/get-support) to turn one off.
</Warning>

To configure one:

1. In the [Console](https://console.upsun.com), open your project and click **<SettingsIcon />**.
2. Click **Project Settings <ChevronIcon />** and then click **Maintenance window**.
3. Choose the recurrence (2 or 4 weeks), weekday, and time (in your project's [timezone](/docs/projects/change-project-timezone)). Click **Save**.

<img src="https://mintcdn.com/upsun-c9761871/LzydLbtLpyS5D1-m/images/ZDD/maintenance-window.png?fit=max&auto=format&n=LzydLbtLpyS5D1-m&q=85&s=1cc635724fec981baf83ac415e076568" alt="Maintenance window in Project settings" width="2884" height="1918" data-path="images/ZDD/maintenance-window.png" />

Based on your recurrence settings, Upsun Cloud calculates the next maintenance date. The Console displays the next scheduled event, and the run itself appears as pending in the [activity log](/docs/observability/logs/access-logs#activity-logs) about 5 days ahead of time.

You can change the recurrence at any time. The new schedule applies from the next maintenance cycle, so a run that's already scheduled keeps its date.

### Reschedule a maintenance window

You can postpone a scheduled maintenance event multiple times within a seven-day window. The new date must fall within the allowable range shown in the Console.

### Turn off a maintenance window

A maintenance window can't be turned off from the Console or CLI. [Contact support](/docs/core-concepts/get-support) to turn one off.

## Zero Downtime Deployments

<Note>
  Zero Downtime Deployments are not supported for projects that use [Varnish](/docs/add-services/varnish). Use the stop-start [deployment strategy](#deployment-strategies) instead if your project uses Varnish.
</Note>

## What is Zero Downtime?

By default, deployments use a stop-start [deployment strategy](#deployment-strategies) (services stop, then restart with updates). Zero Downtime Deployments use a *rolling* deployment strategy, enabling you to deploy changes to your environment without taking your app offline and without interrupting live traffic.

<Info>
  Before using zero-downtime deployments, you must configure a [maintenance window](#maintenance-window). A rolling deployment updates your application, but some service updates, like restarting a database service onto a new version, can't happen during one, since your backing services must keep running the whole time to serve both the original app and its clone. A maintenance window gives Upsun Cloud a separate, scheduled time to apply those service updates instead.
</Info>

## How Zero Downtime works

Instead of stopping services before updating, a temporary copy of your application is created and prepared behind the scenes during the deployment process. Your services work with both the original application and the temporary copy during the whole deployment process, which means that any changes you make to your services during deployment will be applied to the original application. Here's the step-by-step process:

<Steps>
  <Step title="A temporary clone of your application is created">
    * Upsun Cloud starts a temporary container that runs a cloned version of your app.
    * The clone handles all live traffic during this time.
    * Services (for example, Redis) serve both the original app *and* the clone.

          <img src="https://mintcdn.com/upsun-c9761871/7cK3KMJBgO7MXm_y/images/ZDD/ZDD-1.jpg?fit=max&auto=format&n=7cK3KMJBgO7MXm_y&q=85&s=c46e533d4e8d690c33c4dca6ddd4bf8c" alt="A duplicate is made of your current application" width="593" height="446" data-path="images/ZDD/ZDD-1.jpg" />
  </Step>

  <Step title="The original application is updated">
    * The original app is updated with the new code and configuration.
    * The deploy hook is run on the original app.
  </Step>

  <Step title="The clone is removed after deployment">
    * When deployment of the original app is complete, the clone (the temporary container) is shut down and removed.
    * All traffic and services are now applied to the original app only.

          <img src="https://mintcdn.com/upsun-c9761871/7cK3KMJBgO7MXm_y/images/ZDD/ZDD-2.jpg?fit=max&auto=format&n=7cK3KMJBgO7MXm_y&q=85&s=fc23292006eb4284222269535015bab0" alt="The duplicate of your original application is removed" width="593" height="446" data-path="images/ZDD/ZDD-2.jpg" />
  </Step>
</Steps>

<Warning>
  During a zero-downtime deployment, the original app and its clone run simultaneously short period (a few seconds to a couple of minutes).

  **You are billed for extra resources while both app versions active.** If your app’s deployment phase takes longer and uses more resources, expect proportionally higher costs.
</Warning>

### Deployment strategies

#### Stop-start (default)

* Services stop first then restart with the new version
* Deployment is fast but may cause temporary downtime or freezing depending on the application

#### Rolling (ZDD)

* Creates a temporary copy of your services
* Routes traffic to the temporary copy while updating the original services
* Removes the temporary copy once the deployment is complete
* No downtime for users
* Deployment may take longer and use slightly more resources temporarily

### Stop-start vs Rolling (ZDD)

| Feature | Stop-start (default) | Rolling (ZDD) |
| - | - | - |
| **User impact** | Services may be unavailable briefly | Users experience no downtime |
| **Deployment speed** | Fast | Slightly longer |
| **Resource usage** | Standard | Higher temporarily (due to parallel services) |
| **Process** | Stop services → deploy updates → start services | Deploy temporary services → switch traffic → update original services → remove temporary services |
| **Best for** | Small apps, quick updates | Apps requiring uninterrupted availability |
| **Limitations** | Causes downtime/freezetime | Longer deploy time, higher temporary resource use |

### Use cases

| Use Case | Recommendation |
| - | - |
| Code pushes | Suitable |
| Config or environment variable changes | Suitable |
| Stateful service updates (databases, caches) | Not suitable |
| Database schema migrations | Not suitable (unless updates are both backward **and** forward compatible) |

## How to use Zero Downtime Deployments

Before you can run zero-downtime deployments, a project admin needs to [set a maintenance window](#maintenance-window) for the project. We also recommend enabling [manual deployment](#manual-deployment) so you control when each deployment runs.

<Info>
  If you're not a project admin, ask one to set the maintenance window. In the Console, the deployment modal shows when a window hasn't been set yet.
</Info>

<Tabs>
  <Tab title="Using the CLI">
    **On code push**

    ```bash theme={null}
    upsun push --deploy-strategy rolling
    ```

    **With Manual Deployments**

    ```bash theme={null}
    upsun environment:deploy --strategy rolling
    ```
  </Tab>

  <Tab title="Using the Console">
    In the Console, navigate to the environment settings and trigger a deployment from the deployment modal. Select Zero Downtime as a deployment strategy.

    If the project doesn't have a maintenance window yet, you're asked to set one before you can select Zero Downtime.
  </Tab>

  <Tab title="Using the API">
    ```
    POST /projects/{projectId}/environments/{environmentId}/deploy

    {
    "strategy": "rolling"
    }
    ```
  </Tab>
</Tabs>

## Connection handling

During any deployment, long-lived connections like WebSockets or Server-Sent Events (SSE) are dropped.

With ZDD, you can plan for smooth reconnection:

* SSE supports automatic [retry logic](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#retry).

* WebSocket clients should implement reconnect logic.

## Zero Downtime Troubleshooting

This section covers two common scenarios and how to resolve them.

<Info>
  Rolling deployments require a maintenance window. If you get an error saying a maintenance window is required, [set one](#maintenance-window) in **Project settings → Maintenance window**, then deploy again.
</Info>

### Application is slow to start

If your application takes longer to become responsive, traffic might be [switched back to your original application](#how-zero-downtime-works) before it’s fully ready. This can cause temporary errors immediately after deployment.

**Use a post\_start command**

You can use the `post_start` command to ensure your app is fully active before traffic is routed to it. This command can perform checks or wait until your application starts listening on the expected port.

For example, if your framework needs several seconds to initialize (e.g. building caches or database connections), `post_start` can help coordinate the handover so the app receives traffic only when it's ready.

This `post_start` command waits for your application to respond before serving traffic:

```yaml .upsun/config.yaml theme={null}
applications:
  <APP_NAME>:
    web:
      commands:
        post_start: |
          date
          curl -sS --retry 20 --retry-delay 1 --retry-connrefused localhost -o /dev/null
```

For more information about the `post_start` command, visit [web commands](/docs/configure-apps/image-properties/web#post_start-command).

### Deployment fails midway

If deployment fails partway through, one of the applications (either the original or the clone) may remain active in the background while the other continues to serve traffic. This can lead to an increase in resource usage and costs.

To troubleshoot a failure, try one or both of the following:

* [Enable manual deployments](#change-deployment-type) if not already enabled; then, try to manually redeploy the application.
* Deploy the environment using the stop-start strategy to ensure no clones remain active.

<Info>
  If the most recent deployment failed, you can only use the default stop-start strategy.
</Info>

If you still experience issues, [contact support](/docs/core-concepts/get-support).

## Deployment philosophy

Upsun Cloud values consistency over availability, acknowledging that it's nearly impossible to have both.
During a deployment, the [deploy hook](/docs/configure-apps/hooks/hooks-comparison#deploy-hook) may make database changes
that are incompatible with the previous code version.
Having both old and new code running in parallel on different servers could therefore result in data loss.

Upsun believes that a minute of planned downtime for authenticated users is preferable to a risk of race conditions
resulting in data corruption, especially with a CDN continuing to serve anonymous traffic uninterrupted.

This brief downtime affects only the environment being updated.
Deployments to a staging or development branch have no impact on the production environment and cause no downtime.

## What's next

* See how to [configure your app](/docs/configure-apps) for the entire process.
* Learn more about [using build and deploy hooks](/docs/configure-apps/hooks).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.