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:
Shared Across Apps: In a multi-app project, all applications within the same environment share the same cache directory. If
main_appdownloads a dependency to the cache,worker_appcan access it.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.
Comments
Please sign in to leave a comment.