# Hugo Environment-Specific Builds: How Production and Development Modes Work

> Learn how Hugo manages environment-specific builds for production and development. Explore configuration options and CLI flags for distinct site outputs.

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

---

**Hugo handles environment-specific builds through a hierarchical configuration system that checks the `--environment` CLI flag, `HUGO_ENVIRONMENT` environment variable, or `environment` config key, defaulting to "development" when none are specified.**

The **gohugoio/hugo** static site generator treats the build environment as a first-class configuration value that influences cascade rules, template rendering, and asset pipeline behavior. Understanding how Hugo distinguishes between **production** and **development** environments allows developers to conditionally enable features like minification, fingerprinting, and debugging across different deployment contexts.

## Setting the Build Environment

Hugo accepts the target environment through three distinct input methods, evaluated in a specific priority order during the build initialization phase.

### Configuration File

Define the environment explicitly in your site configuration using the `environment` key. In [`config.yaml`](https://github.com/gohugoio/hugo/blob/main/config.yaml) or [`config.toml`](https://github.com/gohugoio/hugo/blob/main/config.toml):

```yaml
environment: production

```

The value is read by `cfg.Environment()` from the loaded configuration and stored in `config.AllProvider.Environment()`, as defined in **[[`config/configProvider.go`](https://github.com/gohugoio/hugo/blob/main/config/configProvider.go)](https://github.com/gohugoio/hugo/blob/master/config/configProvider.go#L34-L38)**.

### Environment Variables

Set `HUGO_ENVIRONMENT` or the shorthand `HUGO_ENV` before invoking the Hugo binary:

```bash
export HUGO_ENVIRONMENT=production
hugo

```

These variables are processed during command execution and injected into external tool environments via `GetExecEnviron` in **[[`common/hugo/hugo.go`](https://github.com/gohugoio/hugo/blob/main/common/hugo/hugo.go)](https://github.com/gohugoio/hugo/blob/master/common/hugo/hugo.go#L102-L115)**.

### CLI Flag Override

The `--environment` (or `-e`) flag takes highest precedence and overrides all other sources:

```bash
hugo server --environment=production

```

This flag is parsed in **[[`commands/commandeer.go`](https://github.com/gohugoio/hugo/blob/main/commands/commandeer.go)](https://github.com/gohugoio/hugo/blob/master/commands/commandeer.go#L546-L550)** and stored in `c.r.environment`, then injected into the configuration during build setup in **[[`commands/hugobuilder.go`](https://github.com/gohugoio/hugo/blob/main/commands/hugobuilder.go)](https://github.com/gohugoio/hugo/blob/master/commands/hugobuilder.go#L1084-L1100)**.

### Default Fallback

When no environment is specified via flag, variable, or config, Hugo falls back to the constant **`EnvironmentDevelopment`** (`"development"`). The production equivalent is defined as **`EnvironmentProduction`** (`"production"`), both declared in **[[`common/hugo/hugo.go`](https://github.com/gohugoio/hugo/blob/main/common/hugo/hugo.go)](https://github.com/gohugoio/hugo/blob/master/common/hugo/hugo.go#L45-L48)**.

## Runtime Environment Usage

Once determined, the environment value propagates through multiple subsystems to enable conditional behavior.

### Cascade Rules and Page Matching

The **PageMatcher** logic in **[[`resources/page/page_matcher.go`](https://github.com/gohugoio/hugo/blob/main/resources/page/page_matcher.go)](https://github.com/gohugoio/hugo/blob/master/resources/page/page_matcher.go#L55-L97)** evaluates environment glob patterns when applying cascade front-matter rules. The matcher checks:

```go
if m.Environment != "" {
    g, err := hglob.GetGlob(m.Environment)
    if err == nil && !g.Match(environment) { return false }
}

```

This allows configuration like:

```yaml
cascade:
  - target:
      environment: production
    minify: true

```

### Template Access

Templates retrieve the current environment through the global Hugo object:

```go
{{ .Site.Hugo.Environment }}  // Returns "development" or "production"

```

This method is implemented in **[[`resources/page/hugoinfo.go`](https://github.com/gohugoio/hugo/blob/main/resources/page/hugoinfo.go)](https://github.com/gohugoio/hugo/blob/master/resources/page/hugoinfo.go#L59-L64)**, where `HugoInfo.Environment()` forwards to the underlying configuration provider.

### Asset Pipeline Integration

External build tools such as PostCSS and Babel receive the environment via `GetExecEnviron`, which explicitly sets `HUGO_ENVIRONMENT` and `HUGO_ENV` in the process environment. This allows asset pipelines to switch behavior based on the build mode without additional configuration.

### Server Confirmation

When running `hugo server`, the active environment is printed to standard output for confirmation, as implemented in **[[`commands/server.go`](https://github.com/gohugoio/hugo/blob/main/commands/server.go)](https://github.com/gohugoio/hugo/blob/master/commands/server.go#L249-L250)**.

## Environment Resolution Flow

The resolution process follows a strict hierarchy during site initialization:

1. **Command Parsing** – [`commands/hugobuilder.go`](https://github.com/gohugoio/hugo/blob/main/commands/hugobuilder.go) evaluates the `--environment` flag first, falling back to environment variables and configuration file values.
2. **Configuration Loading** – `config.LoadConfigFromDir` receives the final environment string and stores it in the `AllProvider` implementation.
3. **Runtime Propagation** – The value becomes accessible via:
   - `.Site.Hugo().Environment()` for templates
   - `PageMatcher.Environment` for cascade matching
   - `GetExecEnviron` for external tool execution

## Practical Implementation Examples

### Switching Analytics in Templates

Use the environment to conditionally load production-only analytics scripts:

```go
{{ if eq .Site.Hugo.Environment "production" }}
  <script async src="https://analytics.example.com/script.js"></script>
{{ end }}

```

### Production-Only Minification

Apply minification exclusively to production builds using cascade rules:

```yaml
cascade:
  - target:
      environment: production
    build:
      minify: true

```

### External Tool Configuration

Configure PostCSS to enable purgecss only in production by checking `process.env.HUGO_ENVIRONMENT`:

```javascript
// postcss.config.js
const purgecss = require('@fullhuman/postcss-purgecss');

module.exports = {
  plugins: [
    ...(process.env.HUGO_ENVIRONMENT === 'production' ? [purgecss()] : [])
  ]
};

```

## Summary

- Hugo accepts environment configuration via the `--environment` CLI flag, `HUGO_ENVIRONMENT` environment variable, or `environment` config key, falling back to `"development"` by default.
- The constants `EnvironmentProduction` and `EnvironmentDevelopment` in [`common/hugo/hugo.go`](https://github.com/gohugoio/hugo/blob/main/common/hugo/hugo.go) define the canonical string values.
- [`commands/hugobuilder.go`](https://github.com/gohugoio/hugo/blob/main/commands/hugobuilder.go) orchestrates the environment resolution during build initialization.
- Cascade rules in [`resources/page/page_matcher.go`](https://github.com/gohugoio/hugo/blob/main/resources/page/page_matcher.go) use glob matching to apply environment-specific front matter.
- Templates access the environment via `.Site.Hugo.Environment`, which retrieves the value from the configuration provider.
- External asset pipelines receive the environment through `HUGO_ENVIRONMENT` and `HUGO_ENV` variables injected by `GetExecEnviron`.

## Frequently Asked Questions

### How do I check the current Hugo environment in a template?

Access the environment through the global Hugo object using `{{ .Site.Hugo.Environment }}`. This returns the string `"development"` or `"production"` (or any custom value you set) and is implemented in [`resources/page/hugoinfo.go`](https://github.com/gohugoio/hugo/blob/main/resources/page/hugoinfo.go) as a wrapper around the configuration provider's `Environment()` method.

### What is the priority order for Hugo environment configuration?

Hugo evaluates sources in the following priority: first the `--environment` CLI flag, then the `HUGO_ENVIRONMENT` or `HUGO_ENV` environment variables, then the `environment` key in your configuration file, and finally defaults to `"development"` if none are provided. This hierarchy is enforced in [`commands/hugobuilder.go`](https://github.com/gohugoio/hugo/blob/main/commands/hugobuilder.go) during the build initialization phase.

### Can I use custom environment names beyond production and development?

Yes, while Hugo defines `EnvironmentProduction` and `EnvironmentDevelopment` constants in [`common/hugo/hugo.go`](https://github.com/gohugoio/hugo/blob/main/common/hugo/hugo.go), you can specify any arbitrary string as the environment value. The `PageMatcher` in [`resources/page/page_matcher.go`](https://github.com/gohugoio/hugo/blob/main/resources/page/page_matcher.go) uses glob patterns, allowing you to target specific environments or groups (e.g., `staging`) in your cascade rules and conditional template logic.

### How does Hugo pass the environment to PostCSS and other external tools?

Hugo injects the current environment into external process environments through the `GetExecEnviron` function in [`common/hugo/hugo.go`](https://github.com/gohugoio/hugo/blob/main/common/hugo/hugo.go). This function explicitly sets both `HUGO_ENVIRONMENT` and `HUGO_ENV` variables before spawning tools like PostCSS or Babel, allowing these pipelines to branch their behavior based on the build mode without requiring separate configuration files.