Last updated on 21st February 2026

Syncing build assets to cloud storage

If your build pipeline generates compiled assets (such as CSS and JS files from Vite, Webpack, or similar tools) that need to be served from cloud storage like Cloudflare R2, you can configure DeployHQ to automatically sync those assets during each deployment.

This is a common pattern for frameworks like Laravel, where the application is deployed to a web server but static assets are served from a CDN-backed object storage bucket. Rather than manually syncing assets after each deployment, you can set up DeployHQ to handle this automatically using a server group.

How it works

When your build pipeline runs (for example, npm run build for Vite), the compiled assets are generated on our build servers. DeployHQ then deploys all files, including the build output, to every server in the deployment.

By creating a server group that contains both your web server and a cloud storage server, DeployHQ will deploy your full application to the web server and only the compiled assets to the cloud storage, all in a single deployment. You control what goes where using per-server excluded files.

Step 1: Add a cloud storage server

In your project, go to Servers & Groups and click New Server. Choose the appropriate protocol for your storage provider:

  • S3-Compatible Storage for Cloudflare R2, Wasabi, Backblaze B2, MinIO, or other S3-compatible services
  • Amazon S3 Bucket for AWS S3

For Cloudflare R2, select S3-Compatible Storage and configure it as follows:

  • Endpoint URL: https://<ACCOUNT_ID>.r2.cloudflarestorage.com
  • Bucket Name: Your R2 bucket name (e.g., my-site-assets)
  • Access Key ID: Your R2 API token access key
  • Secret Access Key: Your R2 API token secret key
  • Path Prefix: Optionally set a prefix if you want assets stored in a subdirectory within the bucket

For detailed instructions on configuring S3-compatible storage providers, see our S3-Compatible Storage guide.

Setting request headers

You may also want to configure request headers on your cloud storage server to set appropriate cache control for your assets. For example, since build tools like Vite include content hashes in filenames, you can safely set long cache durations:

  • Header Key: Cache-Control
  • Header Value: max-age=31536000
  • Pattern: *

Step 2: Create a server group

Go to Servers & Groups and click New Server Group. Give the group a descriptive name (e.g., "Production + Assets") and choose your preferred transfer order:

  • Parallel: Both servers are deployed to at the same time, which is faster
  • Sequential: One server completes its deployment before the next begins

Once the group is created, edit both your existing web server and the new cloud storage server, and assign them to this server group using the Group dropdown at the top of each server's settings page.

For more information on server groups, see Working with multiple servers.

Step 3: Configure excluded files per server

This is the key step. You need to configure excluded files so that the cloud storage server only receives the compiled assets, not your entire application.

Go to Settings > Excluded Files in your project and add exclusion rules for the cloud storage server. When adding each rule, uncheck Exclude this file on all current and future servers? and select only the cloud storage server.

Example: Laravel with Vite

For a Laravel project using Vite, the compiled assets are output to public/build/. You would exclude everything except that directory on your cloud storage server:

Excluded path Applies to
app Cloud storage server only
app/** Cloud storage server only
bootstrap Cloud storage server only
bootstrap/** Cloud storage server only
config Cloud storage server only
config/** Cloud storage server only
database Cloud storage server only
database/** Cloud storage server only
lang Cloud storage server only
lang/** Cloud storage server only
public/index.php Cloud storage server only
public/.htaccess Cloud storage server only
resources Cloud storage server only
resources/** Cloud storage server only
routes Cloud storage server only
routes/** Cloud storage server only
storage Cloud storage server only
storage/** Cloud storage server only
vendor Cloud storage server only
vendor/** Cloud storage server only
artisan Cloud storage server only
composer.json Cloud storage server only
composer.lock Cloud storage server only
package.json Cloud storage server only
package-lock.json Cloud storage server only
vite.config.js Cloud storage server only
.env.example Cloud storage server only

Remember that you need two rules per directory: one for the directory itself and one for its contents (using **). See the Excluded Files documentation for more details on pattern matching.

Alternatively, you can add a .deployignore file to your repository for broader exclusions, though .deployignore does not support per-server rules. If you need different exclusion rules for different servers, use the DeployHQ interface.

Tip: Use whitelisting for simpler configuration

If your project has many top-level directories, it may be easier to exclude everything and then whitelist the assets directory. You can do this by combining a broad exclusion rule with a whitelist rule:

  • ** (exclude everything)
  • !public/build/** (whitelist the build output)

This approach requires fewer rules and is easier to maintain as your project structure changes.

Step 4: Configure your application

Make sure your application is configured to reference assets from your cloud storage URL. In Laravel, this is typically done by setting the ASSET_URL environment variable to point to your R2 bucket's public URL, or by configuring the asset_url value in config/app.php.

Step 5: Deploy

When you trigger a deployment (manually or via automatic deployments), the following happens:

  1. DeployHQ checks out your code and runs your build pipeline (e.g., npm run build)
  2. The compiled assets are generated on the build server
  3. DeployHQ deploys the full application (including built assets) to your web server
  4. DeployHQ deploys only the built assets to your cloud storage server (other files are excluded)

Both transfers happen within the same deployment, so your assets and application code stay in sync.

Alternative approach: SSH commands

If you prefer not to use a server group, you can use an SSH command on your web server to sync assets after each deployment. Add an after deployment command that uses the AWS CLI or a similar tool:

aws s3 sync public/build/ s3://your-bucket-name/ --endpoint-url https://YOUR_ACCOUNT_ID.r2.cloudflarestorage.com

This requires the AWS CLI to be installed on your web server and your R2 credentials to be configured there (for example, via environment variables or an AWS credentials file). The server group approach described above is generally preferred as it keeps everything managed within DeployHQ and does not require additional tools on your server.

Supported storage providers

This guide applies to any S3-compatible storage provider supported by DeployHQ, including:

  • Cloudflare R2
  • Amazon S3
  • Wasabi
  • Backblaze B2
  • DigitalOcean Spaces
  • MinIO
  • Katapult Object Storage

See Configuring S3-Compatible Storage for provider-specific setup instructions.