# How Hugo Data File Loading Works: JSON, YAML, TOML, and Templating Guide

> Learn how Hugo loads JSON, YAML, and TOML data files for O(1) template access. Understand Hugo's data file loading and templating with this comprehensive guide.

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

---

**Hugo loads JSON, YAML, and TOML files from the `data` directory at build time, decodes them using the `metadecoders` package, and exposes the hierarchical structure through the `.Data` map for O(1) template access.**

The `gohugoio/hugo` static site generator treats the `data` directory as a hierarchical key-value store, making **Hugo data file loading** a powerful mechanism for separating structured content from templates. At build start, Hugo walks this directory, unmarshals supported formats, and merges the results into a nested map accessible from any template via dot notation.

## The Data Loading Pipeline

The implementation in [`hugolib/hugo_sites.go`](https://github.com/gohugoio/hugo/blob/main/hugolib/hugo_sites.go) orchestrates a three-stage pipeline that transforms files on disk into structured data available to templates.

### Discovery and File Walking

The process begins with `(*HugoSites).loadData`, which creates a `hugofs.Walkway` to traverse `h.PathSpec.BaseFs.Data.Fs`. For each file encountered, it invokes `(*HugoSites).handleDataFile` to process the individual file. This walk happens early in the build process, ensuring all data is available before template execution begins.

### Reading and Decoding

Once a file is identified, `(*HugoSites).readData` handles the I/O and deserialization. The function opens the file, reads its contents using `helpers.ReaderToBytes`, determines the format via `metadecoders.FormatFromString(f.Ext())`, and unmarshals the content through `metadecoders.Default.Unmarshal`. This centralized decoding in [`parser/metadecoders/decoder.go`](https://github.com/gohugoio/hugo/blob/main/parser/metadecoders/decoder.go) ensures consistent handling across JSON, YAML, and TOML formats.

### Merging into the Data Tree

The final stage occurs in `handleDataFile`, which constructs the hierarchical data structure. The function extracts path components from `r.FileInfo().Meta().PathInfo.Unnormalized().Dir()[1:]` to determine the nested location within the data tree. It walks the map, creating sub-maps as needed, and merges the decoded value.

Precedence rules are critical here: when maps contain duplicate keys, Hugo preserves existing keys and emits a warning. However, slices and scalar values are overwritten. This merging strategy ensures that project-level data files in `data/` override theme-provided files in the theme's `data/` directory, as the project's data directory is processed after the theme's.

## Format Handling and Decoding

The `parser/metadecoders` package provides the abstraction layer for format detection and parsing. The `FormatFromString` function maps file extensions—`.json`, `.yaml`, `.yml`, and `.toml`—to internal `Format` constants. The `Default.Unmarshal` method then dispatches to the appropriate concrete decoder, ensuring that whether your data resides in JSON, YAML, or TOML, the resulting Go data structures are identical from the template's perspective.

## Accessing Data in Templates

Once loaded, the data tree is exposed through two namespaces. The modern approach uses `.Data`, while `.Site.Data` remains available but deprecated. The `(*Site).Data` method in [`hugolib/site.go`](https://github.com/gohugoio/hugo/blob/main/hugolib/site.go) forwards to `hugo.Data`, emitting a deprecation notice when the old path is used.

Because the map is fully constructed before template execution, lookups are O(1) operations using dot notation. For a file at [`data/blog/authors.json`](https://github.com/gohugoio/hugo/blob/main/data/blog/authors.json), the template accesses the content via `{{ .Data.blog.authors }}`. The hierarchical structure mirrors the directory layout, with each subdirectory becoming a nested map key.

## Practical Examples

The following examples demonstrate real-world usage patterns for Hugo data file loading.

**Example 1: Simple JSON Data File**

Create [`data/authors.json`](https://github.com/gohugoio/hugo/blob/main/data/authors.json):

```json
{
  "alice": { "name": "Alice", "email": "alice@example.com" },
  "bob":   { "name": "Bob",   "email": "bob@example.com"   }
}

```

Access in templates:

```go
{{ range $id, $author := .Data.authors }}
  <h2>{{ $author.name }}</h2>
  <p>{{ $author.email }}</p>
{{ end }}

```

**Example 2: Nested Directory with TOML**

Create [`data/team/engineering.toml`](https://github.com/gohugoio/hugo/blob/main/data/team/engineering.toml):

```toml
[[member]]
name = "Carol"
role = "Backend"

[[member]]
name = "Dave"
role = "Frontend"

```

Template usage:

```go
{{ range .Data.team.engineering.member }}
  <p>{{ .name }} – {{ .role }}</p>
{{ end }}

```

**Example 3: Overriding Theme Data with YAML**

Theme provides [`data/settings.yaml`](https://github.com/gohugoio/hugo/blob/main/data/settings.yaml):

```yaml
logo: "/images/theme-logo.png"

```

Project overrides with [`data/settings.yaml`](https://github.com/gohugoio/hugo/blob/main/data/settings.yaml):

```yaml
logo: "/images/custom-logo.png"

```

Template access:

```go
<img src="{{ .Data.settings.logo }}" alt="Site logo">

```

The project's file takes precedence because Hugo processes the site's data directory after the theme's, overwriting scalar values accordingly.

**Example 4: Runtime Resource Loading with transform.Unmarshal**

For data files not in the `data` directory, use resources:

```go
{{ $json := resources.Get "data/metrics.json" | transform.Unmarshal }}
{{ range $metric := $json.metrics }}
  <li>{{ $metric.name }}: {{ $metric.value }}</li>
{{ end }}

```

The `transform.Unmarshal` function in [`tpl/transform/unmarshal.go`](https://github.com/gohugoio/hugo/blob/main/tpl/transform/unmarshal.go) reuses the same `metadecoders` logic, providing consistent decoding for resources loaded at template execution time.

## Summary

- Hugo walks the `data` directory at build start using [`hugolib/hugo_sites.go`](https://github.com/gohugoio/hugo/blob/main/hugolib/hugo_sites.go), processing every JSON, YAML, and TOML file.
- The `parser/metadecoders` package handles format detection and unmarshaling, supporting `.json`, `.yaml`, `.yml`, and `.toml` extensions.
- Data merges into a hierarchical map accessible via `.Data` (preferred) or `.Site.Data` (deprecated), with project files overriding theme files.
- Directory structure mirrors the map hierarchy, enabling dot-notation access like `{{ .Data.team.engineering }}`.
- For dynamic loading, `transform.Unmarshal` provides runtime decoding of resource files using the same underlying decoders.

## Frequently Asked Questions

### What file formats does Hugo support for data files?

Hugo natively supports JSON, YAML, and TOML for data files. The `metadecoders.FormatFromString` function in [`parser/metadecoders/decoder.go`](https://github.com/gohugoio/hugo/blob/main/parser/metadecoders/decoder.go) recognizes file extensions `.json`, `.yaml`, `.yml`, and `.toml`, automatically selecting the appropriate decoder for each file during the build process.

### How do I override a data file provided by a theme?

Place a file with the identical name and path in your project's `data` directory. Hugo processes the site's data directory after the theme's data directory in `(*HugoSites).handleDataFile`, causing scalar and slice values to overwrite theme defaults. Map values merge conservatively, preserving existing keys while emitting warnings for collisions.

### What is the difference between .Site.Data and .Data?

`.Site.Data` is the legacy access path, while `.Data` is the modern namespace introduced to simplify the API. The `(*Site).Data` method in [`hugolib/site.go`](https://github.com/gohugoio/hugo/blob/main/hugolib/site.go) forwards calls to the underlying data structure but emits a deprecation warning when accessed via `.Site.Data`. Both point to the same hierarchical map built from the `data` directory.

### Can I load data files outside the data directory at build time?

Yes, using the `resources.Get` function combined with `transform.Unmarshal`. This approach loads the file as a resource and decodes it using the same `metadecoders.Default.Unmarshal` logic used for the data directory. The template function defined in [`tpl/transform/unmarshal.go`](https://github.com/gohugoio/hugo/blob/main/tpl/transform/unmarshal.go) supports JSON, YAML, and TOML resources located anywhere within the asset directories.