Files
hugo/content/en/functions/css/Build.md
T
Bjørn Erik Pedersen c23d97904f Squashed 'docs/' changes from 0755fb534d..1f8ddb8a52
1f8ddb8a52 content: clarify resources front matter key descriptions
e064ab8528 content: Add deprecation badges to module config page
727ca5563a github: Add push trigger to lint workflow
64dd5c9886 content: Fix typo
c5bc6b6515 github: Fix lint workflow
faec0c3a0a github: Combine linting actions into a single workflow
06112aeaf2 theme: Miscellaneous template edits
75d4902270 theme: Format templates with gotmplfmt
fec2e2a67e content: Document that the language code in a file name must be lowercase
9dbd841ba6 content: Document the src attribute in the Page Resources metadata reference
fd3ffef985 content: Fix "build from source" instructions for Windows
af4c9cd4d7 content: Miscellaneous edits
408d8b2f0a content: Miscellaneous edits
e8804afe6e content: Fix typo
d98276be30 content: Updates for v0.161.0
01b1f8fa12 content: Note merge limitation for slice configuration values
d2b18f0c8d content: Document page matcher usage for cascading values
45e5bd9ab3 content: Update Cloudflare Worker host/deploy guide
b83726b89a content: Document fallback rendering for fenced code blocks
8f1eeb42bc content: Update reference for source code shortcode
e8da56303b content: Add gotmplfmt to list of VS Code extensions
950fabbfd6 content: Update FAQ on feature availability error
6411146d24 content: Update quick start guide
38cc39fd51 content: Add Hugo Shortcodes to list of VS Code extensions
72d98b107b content: Misc updates to get validators to pass
9fb0e1ca35 Add a paragraph about sec boundaries
e6abf5644f content: Improve syntax highlighting documentation
c06193bd1a content: Update go-i18n package reference
ce58fef945 Hugo 0.161.1
c7e0f63385 content: Fix package references
7f15fb3bf9 data: Regen docshelper
7483d53b55 Update HUGO_VERSION to 0.161.0
c4abcdb45f security: Add a bullet point about "pragmatic defaults"
3cd7492862 content: Improve explanation of mount removal in module configurations
4099f07bb9 content: Update GitHub Pages workflow example
a6c9853a58 content: Fix typo
e6f79a938b Update netlify.toml
abda3d6659 content: Update Action versions in GitHub Pages workflow example
55dd288fa9 content: Add GitCMS to front-ends tools list
21081f6d49 content: Remove outdated new-in badges
b2ec263884 content: Update version references
825e0b8ea9 One more CSS var adjustment
85f95a899b Adjust css.Build var docs a little
df48288002 content: Updates for v0.160.0
a82a9b9797 Update HUGO_VERSION to 0.160.0
1155747dc4 content: Improve CSS processing feature description
f6ce893974 content: Add css.Build to features
67b8ed1198 content: Fix typos
0f62a67863 content: Fix typo
dbb42aed4a content: Document the deploy edition
549f30f933 content: De-emphasize references to the extended edition
8f5c9782d4 content: Add Pages CMS to front-ends documentation
b2bfc3af48 Update HUGO_VERSION to 0.159.2
3793156fc5 content: Fix typos
bacd4824ef content: Specify function namespace in example
7f2dc0d40a Regen docs.yml
65a851f731 Update HUGO_VERSION to 0.159.1
ce05fe3fc0 content: Adjust variable references in build script examples
8a04f9fe64 content: Improve hosting build script examples
67962ce05c content: Link to Codeberg Pages 404 handling
fd248f57ed content: Identify esbuild as the foundation for build functions
62f02879fd content: Remove outdated content
553c407f9e content: Miscellaneous corrections
77e2cad088 content: Add new-in badge for usePackageJSON
0746e1e621 Add a page on using npm dependencies in Hugo Modules
8824850f5c Update HUGO_VERSION to 0.159.0

git-subtree-dir: docs
git-subtree-split: 1f8ddb8a5230518f07c50b4b03cba3cae21081c4
2026-05-21 12:22:48 +02:00

13 KiB

title, description, categories, keywords, params
title description categories keywords params
css.Build Bundle, transform, and minify CSS resources.
functions_and_methods
aliases returnType signatures
resource.Resource
css.Build [OPTIONS] RESOURCE

{{< new-in 0.158.0 />}}

Note

The css.Build function is backed by the [evanw/esbuild][] package, providing a mature, high-performance foundation for bundling, transformation, and minification.

Use the css.Build function to:

  • Recursively replace @import statements in CSS files with the content of the imported files
  • Transform syntax for browser compatibility
  • Apply vendor prefixes for browser compatibility
  • Minify the bundled CSS code
  • Create a source map

If an @import statement includes a media query, a feature query, or a cascade layer assignment, the function wraps the imported content in the corresponding @media, @supports, or @layer rule.

Usage

In this example, Hugo bundles the local files referenced by @import statements to create and publish a single resource with inline content.

assets/
└── css/
    ├── components/
    │   ├── a.css
    │   └── b.css
    └── main.css
@import url('https://cdn.jsdelivr.net/npm/the-new-css-reset/css/reset.min.css');

@import './components/a.css';
@import './components/b.css';

.c {color: blue; }
.a { color: red; }
.b { color: green; }
{{ with resources.Get "css/main.css" | css.Build }}
  {{ if hugo.IsDevelopment }}
    <link rel="stylesheet" href="{{ .RelPermalink }}">
  {{ else }}
    {{ with . | fingerprint }}
      <link rel="stylesheet" href="{{ .RelPermalink }}" integrity="{{ .Data.Integrity }}" crossorigin="anonymous">
    {{ end }}
  {{ end }}
{{ end }}
{{ partialCached "css.html" . }}

The generated CSS code:

@import "https://cdn.jsdelivr.net/npm/the-new-css-reset/css/reset.min.css";

.a {
  color: red;
}

.b {
  color: green;
}

.c {
  color: blue;
}

To minify the generated CSS code, use the minify option as described below.

Options

The css.Build function takes an optional map of options to fine-tune bundling, minification, and browser compatibility.

externals
([]string) A slice of path patterns to exclude from bundling. The @import statements for these patterns remain as-is in the generated CSS code. See [details][esb_external].
{{ $opts := dict "externals" (slice "./exclude-these/*" "./exclude-these-too/*") }}
{{ $r := resources.Get "css/main.css" | css.Build $opts }}
loaders
(map) A map of file extensions to loader types. This determines how files with a given extension are processed during bundling. By default, Hugo uses the css loader for .css files and the file loader for all others. Common loaders include:
  • css: Processes the file as a CSS file
  • dataurl: Embeds the file as a base64-encoded data URL
  • empty: Excludes the file from the bundle
  • file: Copies the file to the output directory and rewrites the URL
  • text: Loads the file content as a string

See [details][esb_loader].

{{ $opts := dict "loaders" (dict ".png" "dataurl" ".svg" "dataurl") }}
{{ $r := resources.Get "css/main.css" | css.Build $opts }}
mainFields
([]string) A prioritized slice of field names in a package.json file that determine the CSS entry point of a Node package. The default is ["style", "main"]. See [details][esb_mainfields].

When an @import statement references a Node package, Hugo consults the metadata in the package.json file to find the stylesheet. Use this option to support packages that define a CSS entry point using non-standard fields.

{{ $opts := dict "mainFields" (slice "css" "style" "main") }}
{{ $r := resources.Get "css/main.css" | css.Build $opts }}
minify
(bool) Whether to minify the generated CSS code. Default is false. See [details][esb_minify].
{{ $opts := dict "minify" true }}
{{ $r := resources.Get "css/main.css" | css.Build $opts }}
sourceMap
(string) The type of source map to generate. One of external, inline, linked, or none. Default is none. See [details][esb_sourcemap].
{{ $opts := dict "sourceMap" "linked" }}
{{ $r := resources.Get "css/main.css" | css.Build $opts }}
sourcesContent
(bool) Whether to include the content of the source files in the source map. Default is true. See [details][esb_sourcesContent].
{{ $opts := dict "sourceMap" "linked" "sourcesContent" false }}
{{ $r := resources.Get "css/main.css" | css.Build $opts }}
target
([]string) The target environment for the generated CSS code. This determines which syntax transformations to perform and which vendor prefixes to apply. If unset, no transformations or prefixing are performed. Each element consists of a target name and a version number. Supported targets include chrome, edge, firefox, ie, ios, opera, and safari. See [details][esb_target].
{{ $target := slice "chrome115" "edge115" "firefox116" "ios16.4" "opera101" "safari16.4" }}
{{ $opts := dict "target" $target }}
{{ $r := resources.Get "css/main.css" | css.Build $opts }}

In the example above, the target environment is roughly equivalent to the [browserlist][] "baseline widely available" profile as of March 2026.

targetPath
(string) The path to the generated CSS file, relative to the project's [publishDir][]. If unset, this defaults to the asset's original path with a .css extension.
{{ $opts := dict "targetPath" "css/styles.css" }}
{{ $r := resources.Get "css/main.css" | css.Build $opts }}
vars
{{< new-in 0.160.0 />}}
(map) A map of key-value pairs used to generate CSS variables. The css.Build function injects these variables into the stylesheet when it encounters the hugo:vars internal identifier within an @import statement.
{{ $vars := dict
  "font-family" "\"Times New Roman\", Times, serif"
  "font-size" "24px" 
  "primary-color" "blue" 
}}
{{ $opts := dict "vars" $vars }}
{{ $r := resources.Get "css/main.css" | css.Build $opts }}

In the example above, using the identifier in your CSS allows you to access the values using standard CSS variable syntax.

@import 'hugo:vars';

.element {
  color: var(--primary-color);
  font-family: var(--font-family);
  font-size: var(--font-size);
}

The above produces output equivalent to:

:root {
  --font-family:
    "Times New Roman",
    Times,
    serif;
  --font-size: 24px;
  --primary-color: blue;
}

.element {
  color: var(--primary-color);
  font-family: var(--font-family);
  font-size: var(--font-size);
}

  {{< new-in 0.161.0 />}}

  The map may optionally contain nested maps. Each nested map is exposed as a separate `hugo:vars/<name>` namespace, where `<name>` is the key of the nested map (lowercased). Top-level scalar values and nested maps are independent. A top-level `@import 'hugo:vars'` only includes scalar values, while `@import 'hugo:vars/<name>'` only includes the scalars from the named nested map.

  ```go-html-template
  {{ $vars := dict
    "font-family" "\"Times New Roman\", Times, serif"
    "font-size" "24px"
    "primary-color" "blue"
    "mobile" (dict 
      "font-size" "12px"
      "primary-color" "red" 
    )
  }}
  {{ $opts := dict "vars" $vars }}
  {{ $r := resources.Get "css/main.css" | css.Build $opts }}
  ```

  Because nested imports follow the same rules as regular `@import` statements, you can attach a media query, feature query, or cascade layer assignment to a `hugo:vars/<name>` import.

  ```css
  @import 'hugo:vars';
  @import 'hugo:vars/mobile' (max-width: 650px);

  body {
    background-color: var(--primary-color);
    font-family: var(--font-family);
  }
  ```

  The above produces output equivalent to:

  ```css
  :root {
    --font-family: "Times New Roman", Times, serif;
    --font-size: 24px;
    --primary-color: blue;
  }

  @media (max-width: 650px) {
    :root {
      --font-size: 12px;
      --primary-color: red;
    }
  }

  body {
    background-color: var(--primary-color);
    font-family: var(--font-family);
  }
  ```

  The `vars` option is useful for setting CSS variables within your project configuration.

  {{< code-toggle file=hugo >}}
  [params.theme.style]
  font-family = '"Times New Roman", Times, serif'
  font-size = '24px'
  primary-color = 'blue'

  [params.theme.style.mobile]
  font-size = '12px'
  primary-color = 'red'
  {{< /code-toggle >}}

  ```go-html-template
  {{ $opts := dict "vars" site.Params.theme.style }}
  {{ $r := resources.Get "css/main.css" | css.Build $opts }}
  ```

  When passing a `vars` map to the `css.Build` function, you can use the [`css.Quoted`][] function to explicitly indicate that a value must be treated as a quoted string, most commonly for `font-family` names or the `content` property.

  > [!note]
  > If you're using TailwindCSS and want to use the `vars` option to inject CSS variables, see [this section in the TailwindCSS documentation](./TailwindCSS.md#inject-css-variables-with-vars).

## Example

The example below uses several of the [options](#options) described above to bundle, transform, and minify CSS code.

```go-html-template {file="layouts/_partials/css.html" copy=true}
{{ with resources.Get "css/main.css" }}
  {{ $opts := dict
    "loaders" (dict ".png" "dataurl" ".svg" "dataurl")
    "minify" (cond hugo.IsDevelopment false true)
    "sourceMap" (cond hugo.IsDevelopment "linked" "none")
    "target" (slice "chrome115" "edge115" "firefox116" "ios16.4" "opera101" "safari16.4")
    "targetPath" "css/styles.css"
  }}
  {{ with . | css.Build $opts }}
    {{ if hugo.IsDevelopment }}
      <link rel="stylesheet" href="{{ .RelPermalink }}">
    {{ else }}
      {{ with . | fingerprint }}
        <link rel="stylesheet" href="{{ .RelPermalink }}" integrity="{{ .Data.Integrity }}" crossorigin="anonymous">
      {{ end }}
    {{ end }}
  {{ end }}
{{ end }}
```

Using the options above, Hugo does the following:

- Embeds PNG and SVG images as data URLs in the generated CSS code
- Minifies the output in production but not in development
- Generates an external source map in development but not in production
- Transforms syntax for compatibility with the targeted browser versions
- Adds vendor prefixes for compatibility with the targeted browser versions
- Publishes the generated CSS code to `css/styles.css`
- In production, adds an SRI hash and inserts a file hash into the filename

## Common patterns

The examples below cover the most frequent use cases for referencing resources within your project or within Node packages. These patterns apply to both `@import` statements and the `url()` functional notation used for images and fonts.

All resources referenced by a path, including images, fonts, and stylesheets, must reside in the `assets` directory of the [unified file system](g), or within a Node package.

### Files in the assets directory

To include a stylesheet from the `assets` directory, you can use a bare path, a relative path, or a root-relative path. When you use a bare path, Hugo searches relative to the current stylesheet, then relative to the `assets` directory.

```css {file="/assets/css/main.css"}
/* A bare path */
@import "variables.css";

/* A relative path */
@import "./theme.css";
@import "../layout.css";

/* A root-relative path */
@import "/css/grid.css";

/* A url() reference using the same resolution logic */
.logo { background: url("/images/logo.svg"); }
```

### Node packages

When referencing a Node package by name, Hugo consults the `package.json` file within that package to find the entry point.

```css {file="/assets/css/main.css"}
@import "bootstrap";
```

### Files within a package

To reference a specific file within a Node package, provide the path starting with the package name.

```css {file="/assets/css/main.css"}
@import "bootstrap/dist/css/bootstrap-grid.css";
```

[`css.Quoted`]: /functions/css/quoted/
[`evanw/esbuild`]: https://github.com/evanw/esbuild
[`publishDir`]: /configuration/all/#publishdir
[browserlist]: https://browsersl.ist
[esb_external]: https://esbuild.github.io/api/#external
[esb_loader]: https://esbuild.github.io/api/#loader
[esb_mainfields]: https://esbuild.github.io/api/#main-fields
[esb_minify]: https://esbuild.github.io/api/#minify
[esb_sourcemap]: https://esbuild.github.io/api/#sourcemap
[esb_sourcesContent]: https://esbuild.github.io/api/#sources-content
[esb_target]: https://esbuild.github.io/api/#target