> ## Documentation Index
> Fetch the complete documentation index at: https://infisical.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# CDN caching for static assets

> How to set up CDN caching to prevent version skew issues during deployments

This guide explains a common issue with frontend asset caching during deployments and how to solve it using a CDN.

## The problem: Version skew

Modern frontend build tools like Vite generate content-hashed filenames for static assets (e.g., `main-abc123.js`). Each build produces unique filenames based on file contents. During deployments, this can cause a race condition:

1. User loads `index.html` which references `main-abc123.js`
2. New deployment replaces containers with a new build
3. New containers only serve `main-xyz789.js` (new build)
4. User's browser requests `main-abc123.js` from cached HTML
5. Request returns **404** — the old asset no longer exists

This results in broken pages, failed SPA navigation, and requires users to manually refresh.

<Note>
  This is a documented limitation in Vite's official guidance: [Load Error Handling](https://vite.dev/guide/build#load-error-handling)
</Note>

### Current behavior

Infisical includes a built-in workaround that detects version mismatches and triggers a page reload. While functional, this introduces a noticeable delay for users during deployments.

## The solution: External asset storage

The solution is to store static assets externally (e.g., S3, GCS, Azure Blob) and serve them through a CDN (e.g., CloudFront, Cloud CDN, Cloudflare). Assets are uploaded **before** container deployment, ensuring old versions remain available.

### How it works

```mermaid theme={"dark"}
flowchart LR
    User[User Browser]
    CDN[CDN]
    S3[(Object Storage)]
    App[Your Infrastructure]

    User --> CDN
    CDN -->|"/assets/*"| S3
    CDN -->|"/* (default)"| App
```

The key points:

* **Asset persistence**: Old assets remain available even after new deployments
* **Deployment order**: Upload new assets before deploying new containers
* **Long cache TTL**: Content-hashed files can be cached indefinitely (we recommend 30 days)
* **Automatic cleanup**: Configure lifecycle rules to expire old assets after 30 days

At Infisical, we use **CloudFront + S3** for this purpose, but you can use any CDN and object storage combination that fits your infrastructure.

## Exporting assets

Infisical provides a built-in command to export frontend assets from the Docker image:

```bash theme={"dark"}
# Export as tar archive to stdout
docker run --rm infisical/infisical npm run --silent assets:export > assets.tar

# Extract the archive
tar -xf assets.tar
ls assets/  # Content-hashed JS/CSS files
```

Or export directly to a mounted directory:

```bash theme={"dark"}
docker run --rm -v $(pwd)/cdn-assets:/output \
  infisical/infisical npm run --silent assets:export /output
```

### What gets exported

The command exports the `/assets` directory containing:

* JavaScript bundles (e.g., `main-abc123.js`, `chunk-def456.js`)
* CSS files (e.g., `styles-789xyz.css`)
* Other static assets with content hashes

These files are safe to cache with long TTLs because their filenames change whenever the content changes.

## Integration with your pipeline

The general deployment flow should be:

1. **Build** your new Docker image (or pull the official Infisical image)
2. **Export** assets using `npm run assets:export`
3. **Upload** assets to your object storage
4. **Deploy** the new container version

```bash theme={"dark"}
# Example: Export and upload to S3
docker run --rm infisical/infisical:$VERSION npm run --silent assets:export > assets.tar
tar -xf assets.tar
aws s3 sync assets s3://your-bucket/assets --cache-control "public, max-age=2592000"

# Then deploy your container
```

<Warning>
  Always upload assets **before** deploying the new container. This ensures the assets referenced by the new `index.html` exist before users can access them.
</Warning>
