gotmpl_inline Transform

Execute an inline Go template directly in the panconf configuration. This transform provides the same functionality as gotmpl but without requiring a separate template file.

Usage

node:
  database:
    from_file: database.yaml
  cache:
    from_file: cache.yaml
  config:
    to_file: config.yaml
    transform:
      gotmpl_inline:
        tmpl: |
          services:
            database:
          {{ .database | toYaml | nindent 4 }}
            cache:
          {{ .cache | toYaml | nindent 4 }}

Template Context

Templates have access to:

Variable Description
.nodeName Parsed node data (direct access to fields)
.meta.nodeName.path Node file path (via .meta)
.meta.nodeName.format Node file format (via .meta)
.self Input data in hybrid nodes (nodes with from_* + transform)
.meta.self.path Input file path in hybrid nodes

Template Functions

All Sprig functions are available, plus these panconf-specific functions:

Function Example Description
toYaml {{ .config | toYaml }} Convert value to YAML string
toToml {{ .config | toToml }} Convert value to TOML string
toJson {{ .config | toJson }} Convert value to JSON string (Sprig)
nindent {{ .config | toYaml | nindent 2 }} Add newline and indent (Sprig)
indent {{ .config | toYaml | indent 2 }} Add indent without newline (Sprig)
env {{ env "HOME" }} Get environment variable (Sprig)

Output Format

The template output must be valid YAML or JSON. This is because panconf parses the output to enable:

  1. Re-encoding to different formats (JSON, YAML, TOML)
  2. Using the output as input for other nodes via {{.nodeName}}

Examples

Basic Composition

Compose multiple configs into a single structured output:

node:
  app:
    from_file: app.yaml
  db:
    from_file: database.yaml
  config:
    to_file: config.yaml
    transform:
      gotmpl_inline:
        tmpl: |
          application:
          {{ .app | toYaml | nindent 2 }}
          database:
          {{ .db | toYaml | nindent 2 }}

Extract and Transform

Extract specific fields and transform them:

node:
  source:
    from_file: full-config.yaml
  minimal:
    to_file: minimal.json
    transform:
      gotmpl_inline:
        tmpl: |
          {
            "name": "{{ .source.app.name }}",
            "version": "{{ .source.app.version }}",
            "debug": {{ .source.settings.debug | default false }}
          }

Using Intermediate Nodes

Combine with intermediate nodes for complex pipelines:

node:
  base:
    from_file: base.yaml
  env:
    from_file: production.yaml

  # Intermediate: merge configs (no file written)
  merged:
    transform:
      deepMerge:
        - "{{.base}}"
        - "{{.env}}"

  # Final: wrap merged config with metadata
  final:
    to_file: config.yaml
    transform:
      gotmpl_inline:
        tmpl: |
          metadata:
            generated: "{{ now | date "2006-01-02T15:04:05Z07:00" }}"
            environment: production
          config:
          {{ .merged | toYaml | nindent 2 }}

Iterating Over Glob Documents

Access individual files from a glob input. Glob documents are named by filename stem:

node:
  services:
    from_glob: "services/*.yaml"   # e.g., api.yaml, web.yaml
  manifest:
    to_file: manifest.yaml
    transform:
      gotmpl_inline:
        tmpl: |
          services:
            api:
          {{ .services.api | toYaml | nindent 4 }}
            web:
          {{ .services.web | toYaml | nindent 4 }}

For dynamic iteration over all glob documents, use jq instead:

node:
  services:
    from_glob: "services/*.yaml"
  manifest:
    to_file: manifest.yaml
    transform:
      jq: |
        {
          services: $services | to_entries | map({
            name: .key,
            config: .value
          })
        }

Using Environment Variables

node:
  config:
    from_file: config.yaml
  final:
    to_file: config.json
    transform:
      gotmpl_inline:
        tmpl: |
          {
            "environment": "{{ env "APP_ENV" | default "development" }}",
            "config": {{ .config | toJson }}
          }

Conditional Content

node:
  config:
    from_file: config.yaml
  output:
    to_file: output.yaml
    transform:
      gotmpl_inline:
        tmpl: |
          app:
            name: {{ .config.name }}
          {{- if .config.debug }}
            debug:
              enabled: true
              level: {{ .config.debugLevel | default "info" }}
          {{- end }}

Comparison with gotmpl

Aspect gotmpl gotmpl_inline
Template location Separate file Inline in panconf config
Additional data files Supported via args Not supported
.Data variable Available Not available
Best for Complex templates, reusable templates Simple transformations, composition

Use gotmpl_inline when:

  • The template is short and specific to this config
  • You want everything in one file
  • You're mainly composing/restructuring existing inputs

Use gotmpl when:

  • The template is complex or reusable
  • You need additional data files merged into .Data
  • You prefer templates in separate files

Common Patterns

Wrap Config with Metadata

gotmpl_inline:
  tmpl: |
    version: "1.0"
    generated: "{{ now | date "2006-01-02" }}"
    data:
    {{ .source | toYaml | nindent 2 }}

Merge and Restructure

gotmpl_inline:
  tmpl: |
    combined:
      from_a: {{ .a.value }}
      from_b: {{ .b.value }}
      nested:
      {{ .c | toYaml | nindent 4 }}

Generate Lists

gotmpl_inline:
  tmpl: |
    items:
    {{- range $key, $val := .config }}
      - key: {{ $key }}
        value: {{ $val }}
    {{- end }}