Assets Management

June 2, 2026 · View on GitHub

Most frontend projects bundle static media — icons, images, videos, audio — directly into the application build. This is convenient but has a real cost: replacing any asset requires a full rebuild and redeploy. For web applications this is an inconvenience. For mobile applications it is a much bigger problem, because a new release also means going through the app store review process.

The alternative is to treat media assets as infrastructure: store them on S3, deploy them independently from the application code, and have the app reference them by URL. The application ships once; the assets can change at any time without touching the build.

When this matters

A designer wants to update an icon. With assets on S3, they upload the new file and the change is live immediately — no build, no deployment, no review cycle.

A seasonal banner needs to change. Swap the image on S3. Done.

An A/B test needs a different hero image for a subset of users. Upload both variants, toggle the URL in configuration.

The same principle extends beyond images. A JSON config file on S3 can hold feature flags, remote configuration, or localization strings. Changing product behavior or copy becomes a file upload rather than a software release. This is particularly valuable when the pace of business change is faster than the pace of software deployments.

How it works

Assets live in a dedicated assets/ directory at the root of the monorepo. During CI/CD, this directory is synced to S3 independently of the application build. The application references assets by their S3 URL rather than bundling them as imports.

assets/
  icons/
  images/
  config/
    feature-flags.json

In production, the application fetches assets from S3 via CloudFront. Updating an asset is a single aws s3 cp command in the CI pipeline — or a manual upload for non-engineers.

Local development

In local development, a lightweight static server replicates the S3 behavior:

npm run dev:assets   # serves assets/ at http://localhost:4000

The application reads a base URL from an environment variable. In development this points to localhost:4000. In production it points to the CloudFront distribution. No code changes are needed between environments.

What belongs in assets

Not everything should be externalized. The rule is straightforward: if an asset is referenced by content or configuration, it belongs on S3. If it is tightly coupled to a specific component or UI state, it belongs in the bundle.

Good candidates for S3: marketing images, banners, illustrations, icons that a designer might update, localization files, remote configuration, feature flags.

Poor candidates: component-level SVG icons used in code, loading spinners, error state illustrations tied to specific error codes.