Articles in this section

Managing Multi-App Projects with Root-Level Build Tasks

Overview

In a multi-app setup on Upsun, each application container is traditionally built in isolation. However, many modern projects (especially Monorepos or those using Git submodules) have shared dependencies or "root-level" tasks—such as a global npm install or shared asset compilation—that need to run before individual apps are processed.

This article explains how to configure a "Main" application to handle root-level build tasks and how the Build Cache is shared to ensure efficiency across all application containers.


1. The Strategy: Root-Level Build Execution

Since Upsun builds each app separately, running a full npm install or composer install inside every single app container is redundant and slow.

The Solution: Designate one application as the "primary" or "main" app. This app will use a source.root of / to gain access to the entire repository and execute the global build tasks.

Configuration Example

In your .upsun/config.yaml, define your apps as follows:

YAML

 
applications:
  # The 'main' app performs root-level tasks
  main_app:
    source:
      root: "/"
    hooks:
      build: |
        set -e
        # Perform global tasks at the repo root
        npm install
        npm run build-shared-assets

  # Subsequent apps only build their specific sub-directory
  worker_app:
    source:
      root: "apps/worker"
    hooks:
      build: |
        set -e
        # Only run worker-specific tasks

2. Understanding the Build Cache ($PLATFORM_CACHE_DIR)

To avoid re-downloading thousands of packages on every deployment, Upsun provides a persistent directory called the Build Cache.

How Sharing Works

The $PLATFORM_CACHE_DIR is unique in two ways:

  1. Shared Across Apps: In a multi-app project, all applications within the same environment share the same cache directory. If main_app downloads a dependency to the cache, worker_app can access it.

  2. Persistent Across Builds: This directory is not wiped between deployments. It is a "living" storage area used to store things like .npm, .composer/cache, or .yarn-cache.

Visualizing the Multi-App Build Flow

The diagram below illustrates how multiple application containers interact with the unified Build Cache during the build phase.


3. Best Practices for Build Cache Efficiency

Link Your Dependency Managers

By default, package managers often try to store their cache in the home directory (~/.npm). Since the home directory is not persistent between builds, you should symlink these to the $PLATFORM_CACHE_DIR.

Example Build Hook Script:

Bash

 
# 1. Create the persistent folder in the cache if it doesn't exist
mkdir -p $PLATFORM_CACHE_DIR/.npm

# 2. Symlink the application's local npm cache to the persistent directory
ln -s $PLATFORM_CACHE_DIR/.npm ~/.npm

# 3. Run your install
npm install

Avoid Storing Build Artifacts

Do not use the cache for the final compiled code (e.g., your dist/ or vendor/ folders).

  • The Cache is for "ingredients" (downloaded packages).

  • The App Directory ($PLATFORM_APP_DIR) is for the "final meal" (compiled code).

Anything left in $PLATFORM_APP_DIR at the end of the build hook becomes part of the read-only image deployed to production.


4. Troubleshooting

If your cache becomes corrupted or you need a "clean slate," you can clear it using the Upsun CLI:

Bash

 
upsun project:clear-build-cache

Note: Clearing the cache will make your next build significantly slower as all dependencies must be re-downloaded.

Was this article helpful?
0 out of 0 found this helpful

Comments

0 comments

Please sign in to leave a comment.