How the Asset Management System Handles Relative Paths in Astro Big Doc: Development vs Production

The astro-big-doc asset pipeline uses a zero-copy runtime route for relative paths during development, but copies and optionally hashes assets into dist/_astro during production builds based on the copy_assets configuration flag.

The astro-big-doc repository implements a dual-mode asset management system that handles relative paths differently depending on whether you are running a development server or building for production. Understanding how the asset management system handles relative paths across these environments is crucial for debugging broken images and optimizing cache strategies. The behavior is controlled primarily through the copy_assets flag in config.js and the resolution logic in src/libs/assets.js.

Development Mode: Zero-Copy Asset Serving

The Runtime Asset Route

In development, copy_assets defaults to false. When you reference a relative asset path like images/logo.png in your Markdown, the system does not copy the file. Instead, the relAssetToUrl function in src/libs/assets.js returns a URL prefixed with /assets/, such as /assets/images/logo.png.

This request is handled by the dynamic route at src/pages/assets/[...path].js. The route resolves the file directly from the source content directory (config.content_path) using the remove_base helper to strip any configured base path. No files are duplicated on disk, enabling instant updates when you modify assets during development.

Path Resolution Without Copying

The assetToUrl function serves as the main entry point for all asset references. For relative paths, it delegates to relAssetToUrl, which checks the copy_assets configuration. When this flag is false, the function bypasses the copying logic entirely and returns the runtime route URL, ensuring the browser fetches the file from the source location.

Production Build: Copied and Hashed Assets

Enabling Asset Copying

When you set copy_assets to true (typically via environment variables in CI/CD), the asset management system shifts to a static copying strategy. The relAssetToUrl function now invokes relAssetToUrlCopy for every relative asset path encountered during the build.

This helper determines the absolute source file path by joining config.content_path with the relative directory and filename. It then copies the file into the output directory, defaulting to dist/_astro. If the assets_hash_dir configuration is true (the default), the filename is hashed using its content for cache-busting purposes.

Hashing for Cache Busting

The relAssetToUrlCopy function generates hashed filenames like logo-a1b2c3d4.png when assets_hash_dir is enabled. This ensures that when you redeploy with modified assets, browsers fetch the new versions rather than using stale cached files.

If you disable hashing by setting assets_hash_dir to false, the system preserves the original directory structure within _astro, resulting in URLs like /_astro/images/logo.png. This is useful when you need predictable filenames for external referencing.

Core Asset Resolution Logic in assets.js

Key Functions Overview

The src/libs/assets.js file contains the primary logic for how the asset management system handles relative paths:

  • assetToUrl(path, dirpath): The universal entry point. Distinguishes between absolute paths (starting with /), external URLs, and relative paths.
  • relAssetToUrl(relpath, dirpath): Handles relative paths specifically. Checks config.copy_assets to decide between development-style routing or production copying.
  • relAssetToUrlCopy(relpath, dirpath): Executes the copy-and-hash logic for production builds. Constructs absolute paths, manages the dist/_astro output, and generates hashed filenames when configured.
  • remove_base(path) and add_base(path): Utility functions that handle the optional config.base path prefix, ensuring URLs remain correct when the site is deployed to a subdirectory.

Base Path Handling

When your site is deployed to a subdirectory (e.g., /docs), the config.base setting ensures all asset URLs are prefixed correctly. The add_base function prepends this base to generated URLs, while remove_base strips it when mapping incoming requests back to filesystem paths in the development asset route.

Configuration Reference

config.js Settings

The behavior of the asset pipeline is centralized in config.js:

// config.js
export default {
  copy_assets: false,        // Toggle between dev (false) and production (true) modes
  copy_assets_dir: "_astro", // Output directory for copied assets
  assets_hash_dir: true,     // Enable content hashing for cache busting
  base: "",                  // Optional base path (e.g., "/docs")
  content_path: "content"    // Source directory for content and assets
}

To switch to production mode, set the environment variable before building:

COPY_ASSETS=true npm run build

Practical Examples

Development Usage

Reference an image in your Markdown content:

![Architecture Diagram](diagrams/system-overview.png)

During development, this generates:

<img src="/assets/diagrams/system-overview.png" alt="Architecture Diagram">

The file is served directly from content/diagrams/system-overview.png via the dynamic route at src/pages/assets/[...path].js.

Production Build Commands

Enable asset copying and hashing for deployment:


# Enable production asset handling

export COPY_ASSETS=true
export ASSETS_HASH_DIR=true

# Build the site

npm run build

The build process copies content/diagrams/system-overview.png to dist/_astro/system-overview-a1b2c3d4.png and updates the HTML to:

<img src="/_astro/system-overview-a1b2c3d4.png" alt="Architecture Diagram">

Summary

  • Development mode (copy_assets: false) keeps assets in place and serves them via a dynamic runtime route (/assets/...), enabling instant updates without file copying.
  • Production mode (copy_assets: true) copies assets to dist/_astro, optionally hashes filenames for cache busting (assets_hash_dir: true), and generates static URLs pointing to the copied files.
  • The asset resolution logic lives in src/libs/assets.js, with key functions relAssetToUrl and relAssetToUrlCopy handling the mode-specific behavior.
  • Base path support via config.base ensures correct URL generation when deploying to subdirectories, managed by add_base and remove_base helpers.

Frequently Asked Questions

How do I enable production asset copying in astro-big-doc?

Set the COPY_ASSETS environment variable to true before running the build command. This switches the asset management system from runtime serving to static copying mode, placing assets in the dist/_astro directory with optional content hashing.

Why are my images broken in development but work in production?

If images return 404 during development, verify that copy_assets remains false (the default) and that your files exist in the content directory relative to your Markdown files. The development server expects to serve these through the /assets/ dynamic route, not from the dist folder.

What is the difference between hashed and non-hashed asset filenames?

When assets_hash_dir is true (default in production), the system appends a content hash to filenames (e.g., logo-a1b2c3d4.png), ensuring browsers fetch updated versions when the file changes. When set to false, the original directory structure and filenames are preserved inside _astro, useful when you need predictable URLs for external systems.

Where does the asset resolution logic live in the codebase?

The core logic resides in src/libs/assets.js, specifically within the relAssetToUrl and relAssetToUrlCopy functions. Development-time serving is handled by src/pages/assets/[...path].js, while configuration defaults are defined in config.js.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →