Platform.sh is now Upsun. Click here to learn more
Upsun User Documentation

Build and deploy

Each time you push a change to your app through Git or activate an environment, 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.

The steps in the build and deploy process

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

The build Anchor to this heading

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 Anchor to this heading

  1. Validate configuration: The configuration is checked by validating the .upsun directory and scanning the repository for any app configuration to validate.

  2. Pull container images: Any container images that have been built before and that don’t have any changes are pulled to be reused.

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

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

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

  6. Freeze app container: The file system is frozen and produces a read-only container image, which is the final build artifact.

The deploy Anchor to this heading

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 Anchor to this heading

  1. Hold requests: Incoming idempotent requests (like GET, PUT, DELETE but not POST, PATCH etc.) are held.
  2. Unmount current containers: Any previous containers are disconnected from their file system mounts.
  3. Mount file systems: The file system is connected to the new containers. New branches have file systems cloned from their parent.
  4. Expose services: Networking connections are opened between any containers specified in your app and services configurations.
  5. Run (pre-) start commands: The 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.
  6. 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.
  7. Serve requests: Incoming requests to your newly deployed application are allowed.

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

Deployment types Anchor to this heading

Upsun 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) Anchor to this heading

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 Anchor to this heading

When enabled, manual deployment lets you control when deployments happen. This means that changes will be staged but not deployed until explicitly triggered by the user. This type of 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

Change deployment type Anchor to this heading

You can adjust deployment behavior in your environment.

Use the following command in the CLI to view or change the deployment type:

upsun environment:deploy:type

The output should look similar to the example below:

Selected project: [my-project (ID)] Selected environment: main (type: production) Deployment type: manual

For more information about how this command works, use:

upsun environment:deploy:type --help
To switch to manual, navigate to the environment settings in the Console and select the manual deployments option.

Trigger deployment manually Anchor to this heading

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

Deploy staged changes to your chosen environment using the following command:

upsun environment:deploy

The output should look similar to the example below:

Deploying staged changes: +---------------+---------------------------+-----------------------------------------------------------+---------+ | ID | Created | Description | Result | +---------------+---------------------------+-----------------------------------------------------------+---------+ | 5uh3xwmkh5boq | 2024-11-22T14:01:10+00:00 | Patrick pushed to main | failure | | fno2qiodq7e3c | 2024-11-22T13:06:18+00:00 | Arseni updated resource allocation on main | success | | xzvcazrtoafeu | 2024-11-22T13:01:10+00:00 | Pilar added variable HELLO_WORLD to main | success | | fq73u53ruwloq | 2024-11-22T12:06:17+00:00 | Pilar pushed to main | success | +---------------+---------------------------+-----------------------------------------------------------+---------+
In the Console, a deploy button will be visible in the environment whenever changes are staged. Click this button to deploy your staged changes.

Trigger the deployment of staged changes with the following:

POST /projects/{projectId}/environments/{environmentId}/deploy

Zero Downtime Deployments Anchor to this heading

What is Zero Downtime? Anchor to this heading

Zero Downtime Deployments (ZDD) let you update environments without interrupting live traffic. By default, deployments use stop-start (services stop, then restart with updates). With ZDD, you can switch to a rolling strategy that keeps your app online during updates.

How Zero Downtime works Anchor to this heading

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:

A clone is made of your current application

  • Upsun starts a temporary container running a cloned version of your app.
  • The cloned app begins handling all live traffic during this time.
  • Your services (for example Redis) will serve the cloned app as well as the original app.

A duplicate is made of your current application

Cloned apps are removed after deployment

  • When deployment is complete, the clone of your app is shut down and removed.
  • All traffic and services are now solely applied to the original app alone.

The duplicate of your original application is removed

Deployment strategies Anchor to this heading

Stop-start (default) Anchor to this heading

  • 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) Anchor to this heading

  • 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) Anchor to this heading

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 Anchor to this heading

Use Case Recommendation
Code pushes Suitable
Config or environment variable changes Suitable
Stateful services (databases, caches) Not suitable
DB schema migrations Not suitable (except if updates are backward and forward compatible)

How to use Zero Downtime Deployments Anchor to this heading

Default (stop-start)

upsun environment:deploy --strategy stopstart

Zero Downtime (rolling)

upsun environment:deploy --strategy rolling
In the Console, navigate to the environment settings and trigger a deployment from the deployment modal. Select Zero Downtime as a deployment strategy.
POST /projects/{projectId}/environments/{environmentId}/deploy { "strategy": "rolling" }

Connection handling Anchor to this heading

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 (MDN reference).

  • WebSocket clients should implement reconnect logic.

Zero Downtime Troubleshooting Anchor to this heading

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

Application is slow to start Anchor to this heading

If your application takes longer to become responsive, traffic might be switched back to your original application before it’s fully ready. This can cause temporary errors immediately after deployment.

Deployment fails midway Anchor to this heading

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.

Deployment philosophy Anchor to this heading

Upsun values consistency over availability, acknowledging that it’s nearly impossible to have both. During a deployment, the 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.

That brief downtime applies only to the environment changes are being pushed to. Deployments to a staging or development branch have no impact on the production environment and cause no downtime.

What’s next Anchor to this heading