# Hugo Mount Configuration: How to Mount Content from Different Sources

> Learn how Hugo handles content mounting from various sources using overlay mounts to merge directories and files onto component roots like content and static.

- Repository: [GoHugo.io/hugo](https://github.com/gohugoio/hugo)
- Tags: how-to-guide
- Published: 2026-02-28

---

**Hugo handles content from different sources by merging overlay mounts that map arbitrary directories or files from your project or imported modules onto component roots like `content`, `assets`, `static`, and `layouts`, processed through collection, normalization, and filesystem creation stages.**

Hugo's **mount configuration** system creates a unified filesystem by overlaying directories from multiple sources onto logical component paths. According to the `gohugoio/hugo` source code, this mechanism processes module imports through [`modules/collect.go`](https://github.com/gohugoio/hugo/blob/main/modules/collect.go), validates mount definitions in [`modules/config.go`](https://github.com/gohugoio/hugo/blob/main/modules/config.go), and constructs the final overlay filesystem in [`hugofs/rootmapping_fs.go`](https://github.com/gohugoio/hugo/blob/main/hugofs/rootmapping_fs.go) that presents a single coherent view of content scattered across your project, themes, and external modules.

## The Three Stages of Mount Processing

Hugo processes mount configurations through a three-stage pipeline implemented in [`modules/collect.go`](https://github.com/gohugoio/hugo/blob/main/modules/collect.go). This ensures that every module import contributes its files safely to the unified filesystem.

### Stage 1: Collecting Module Configuration with `applyMounts`

The mount collection process begins in `applyMounts` (lines 416-459 of [`modules/collect.go`](https://github.com/gohugoio/hugo/blob/main/modules/collect.go)). For each module import, Hugo determines which directories should be mounted:

- If `import.NoMounts` is `true`, the module contributes no files to the filesystem.
- If the import defines explicit `module.mounts`, those definitions take precedence.
- If no mounts are declared, Hugo creates **default mounts** for every component folder that exists in the module (such as `content`, `assets`, `static`, or `layouts`).

This fallback mechanism ensures that traditional themes work immediately without explicit mount configuration while allowing advanced users to define precise mappings.

### Stage 2: Normalizing and Validating Mounts with `normalizeMounts`

Once collected, raw mount definitions pass through `normalizeMounts` (lines 711-749 of [`modules/collect.go`](https://github.com/gohugoio/hugo/blob/main/modules/collect.go)) for validation and transformation:

- **Path cleaning**: Source and target paths are cleaned and made absolute relative to the module's root directory.
- **Source restrictions**: For non-project modules, sources must be local paths; absolute sources are permitted only in the main project.
- **Special handling**: The function manages `node_modules` imports and prevents mounting of the public folder or [`hugo_stats.json`](https://github.com/gohugoio/hugo/blob/main/hugo_stats.json).
- **Filter creation**: The `files` parameter converts into an inclusion/exclusion filter using glob patterns (e.g., `"! drafts/*"` excludes files).
- **Language migration**: The deprecated `lang` field migrates to the newer `sites.matrix` representation during initialization.

This stage ensures that only safe, well-formed mounts reach the filesystem layer.

### Stage 3: Creating the Overlay Filesystem with `RootMappingFs`

Validated mounts feed into the `RootMappingFs` structure defined in [`hugofs/rootmapping_fs.go`](https://github.com/gohugoio/hugo/blob/main/hugofs/rootmapping_fs.go). When Hugo requests content from a component root, the `Mounts` method (lines 36-64) resolves the physical sources:

1. **Prefix matching**: The method looks up every `RootMapping` whose target path is a prefix of the requested component path.
2. **Filesystem construction**: For each match, Hugo creates a `BasePathFs` wrapping the underlying filesystem. If the mount includes a `files` filter, it wraps this with a filename filter filesystem.
3. **Directory decoration**: The filesystem passes through `decorateDirs` to attach metadata.
4. **Stacking**: The resulting `FileMetaInfo` objects stack according to mount weight, with later mounts winning precedence in case of path conflicts.

This overlay approach allows content from your project, a theme, and `node_modules` to coexist under a single logical `content` directory without physical copying.

## Configuring Mounts in Your Project

Hugo exposes mount configuration through the `module.mounts` section of your site configuration, supporting both TOML and YAML formats.

### Basic Mount Configuration

Define mounts by specifying the source directory and the target component root:

```toml
[module]
  [[module.mounts]]
    source = "content"
    target = "content/blog"

  [[module.mounts]]
    source = "node_modules/bootstrap/dist/js"
    target = "assets/js/bootstrap"

```

In this example, the project's `content` directory mounts to `content/blog`, effectively relocating all posts under the `/blog/` URL path. The second mount makes Bootstrap's JavaScript files available under `assets/js/bootstrap` for Hugo's asset pipeline.

### Advanced Mount Options with File Filtering

Mounts support granular control through the `files` parameter, which accepts glob patterns for inclusion or exclusion:

```toml
[[module.mounts]]
  source = "content"
  target = "content"
  files  = ["! drafts/*", "! **/private.md"]

```

The `!` prefix excludes matching files. This configuration mounts the content directory but omits any files in `drafts/` subdirectories and any file named [`private.md`](https://github.com/gohugoio/hugo/blob/main/private.md). According to [`modules/config.go`](https://github.com/gohugoio/hugo/blob/main/modules/config.go), these patterns convert into an `InclusionFilter` applied during the `BasePathFs` creation stage.

## Summary

Hugo's mount configuration system creates a **unified filesystem** by overlaying directories from multiple sources onto component roots. Key implementation details include:

- **Three-stage processing**: Mounts collect via `applyMounts` in [`modules/collect.go`](https://github.com/gohugoio/hugo/blob/main/modules/collect.go), normalize through `normalizeMounts`, and resolve through `RootMappingFs.Mounts` in [`hugofs/rootmapping_fs.go`](https://github.com/gohugoio/hugo/blob/main/hugofs/rootmapping_fs.go).
- **Automatic defaults**: Modules without explicit mounts receive default mappings for existing component folders (`content`, `assets`, `static`, `layouts`).
- **File filtering**: The `files` parameter supports glob patterns for selective inclusion or exclusion of content.
- **Overlay precedence**: Later mounts in the configuration stack take precedence, allowing project files to override theme content.

## Frequently Asked Questions

### What is the difference between source and target in Hugo mounts?

The **source** parameter specifies the physical directory path relative to the module's root, while the **target** defines the logical location within Hugo's unified filesystem where that content appears. For example, mounting `source = "content"` to `target = "content/blog"` makes files physically located in the project's `content/` folder available under the `/blog/` URL path.

### Can I mount content from node_modules or external directories?

Yes, Hugo explicitly supports mounting from `node_modules` and other external directories. In `normalizeMounts` within [`modules/collect.go`](https://github.com/gohugoio/hugo/blob/main/modules/collect.go), special handling exists for `node_modules` imports. You can mount assets from installed packages by defining a mount with `source = "node_modules/some-package/dist"` and `target = "assets/js/lib"`. However, absolute source paths are restricted to the main project; imported modules must use relative paths.

### How does Hugo handle file conflicts when multiple mounts target the same path?

Hugo resolves conflicts through **mount weight and stacking order**. When `RootMappingFs.Mounts` in [`hugofs/rootmapping_fs.go`](https://github.com/gohugoio/hugo/blob/main/hugofs/rootmapping_fs.go) collects matching filesystems, it stacks them according to their configuration sequence. Later mounts win precedence, meaning if both a theme and your project mount to `content/posts`, the project's version takes priority. The `decorateDirs` function attaches metadata that helps Hugo determine which physical source provides each file.

### What happens if a module has no explicit mounts defined?

If a module lacks explicit `module.mounts` configuration, Hugo automatically creates **default mounts** during the `applyMounts` stage in [`modules/collect.go`](https://github.com/gohugoio/hugo/blob/main/modules/collect.go). The collector inspects the module's directory structure and generates implicit mounts for every standard component folder that exists: `content`, `assets`, `static`, `layouts`, `data`, and `i18n`. This ensures backward compatibility with traditional Hugo themes while still utilizing the overlay filesystem architecture.