WizardOps Hat Background
Grimoire → TutorialsGetting Started with Conjure: Template-Driven Configuration Generation
Getting Started with Conjure: Template-Driven Configuration Generation
Tutorials

Getting Started with Conjure: Template-Driven Configuration Generation

>_
Joshua Tracy
📜 Inscribed on February 1, 2026
12 minute incantation

Configuration sprawl hits every engineering team eventually. Kubernetes manifests, Terraform modules, server configs, API payloads, application configs, reusable templates, or any text file of your choice. Conjure fixes this. Define a template once, describe its variables, and generate finished configs on demand.

Prerequisites

You'll need curl and a Unix-like shell (Linux or macOS).

NoteWindows users: the rest of this post uses Unix shell commands. You can follow along using WSL2, or follow the full step-by-step guide at conjure.wizardops.dev/docs/getting-started which has Windows-specific instructions throughout.

Install

Run the one-liner for your platform. The script detects your OS and architecture automatically.

Linux & macOS
$ curl -sfL https://raw.githubusercontent.com/WizardOpsTech/conjure/main/install.sh | sh
Windows (PowerShell)
$ irm https://raw.githubusercontent.com/WizardOpsTech/conjure/main/install.ps1 | iex

Then verify the install:

$ conjure --versionconjure version 1.0.0

Set Up a Workspace

Create a project directory with templates and bundles folders, then write a conjure.yaml. The $PWD variable fills in your current directory automatically -- no manual path editing needed.

Default config location if --config is not provided is ~/.conjure.yaml

$ mkdir -p my-project/templates my-project/bundles$ cd my-project$ cat > conjure.yaml << EOFtemplates_source: localbundles_source: localtemplates_local_dir: $PWDbundles_local_dir: $PWDEOF

Create a Template

Each template lives in templates/{name}/{version}/ with two files: conjure.json for metadata and template.tmpl for the Go template.

Create the directory and write the metadata file:

$ mkdir -p templates/greeting/1.0.0$ cat > templates/greeting/1.0.0/conjure.json << 'EOF'{  "schema_version": "v1",  "template_name": "greeting",  "template_type": "txt",  "template_description": "A simple greeting template",  "variables": [    {      "name": "name",      "type": "string",      "description": "Your name",      "default": ""    },    {      "name": "team",      "type": "string",      "description": "Your team name",      "default": "Platform Engineering"    }  ]}EOF

Inspect the metadata file to confirm it was written correctly:

$ cat templates/greeting/1.0.0/conjure.json{  "schema_version": "v1",  "template_name": "greeting",  "template_type": "txt",  "template_description": "A simple greeting template",  "variables": [    {      "name": "name",      "type": "string",      "description": "Your name",      "default": ""    },    {      "name": "team",      "type": "string",      "description": "Your team name",      "default": "Platform Engineering"    }  ]}

Then write the template file:

$ cat > templates/greeting/1.0.0/template.tmpl << 'EOF'Hello, {{ .name }}!Welcome to the {{ .team }} team.EOF

Inspect the template:

$ cat templates/greeting/1.0.0/template.tmplHello, {{ .name }}!Welcome to the {{ .team }} team.

Generate from a Template

Pass variables with --var flags and write the output to a file with -o.

$ conjure template greeting \    --var name="DevOps Engineer" \    -o greeting.txt --config conjure.yamlUsing template: greeting v1.0.0 (source: local)Using metadata: A simple greeting template Variables:  name = DevOps Engineer  team = Platform Engineering Template rendered successfullyOutput written to: greeting.txt

Inspect the generated file:

$ cat greeting.txtHello, DevOps Engineer!Welcome to the Platform Engineering team.

Interactive Mode

Do not pass any --var or -f flags and Conjure automatically enters interactive mode, prompting you for each variable with its description and default.

$ conjure template greeting -o greeting.txt --config conjure.yamlUsing template: greeting v1.0.0 (source: local)Using metadata: A simple greeting template ? Enter value for 'name': SRE Lead? Enter value for 'team': Infrastructure Template rendered successfullyOutput written to: greeting.txt

Values Files and Precedence

Store variables in YAML files for repeatability. CLI --var flags beat values files, which beat template defaults.

$ mkdir -p values$ cat > values/team-defaults.yaml << 'EOF'name: Platform Engineerteam: Cloud InfrastructureEOF

Inspect the values file:

$ cat values/team-defaults.yamlname: Platform Engineerteam: Cloud Infrastructure
$ conjure template greeting \    -f values/team-defaults.yaml \    --var name="Senior SRE" \    -o greeting.txt --config conjure.yamlUsing template: greeting v1.0.0 (source: local)Using metadata: A simple greeting template Variables:  name = Senior SRE  team = Cloud Infrastructure Template rendered successfullyOutput written to: greeting.txt

Create a Bundle

Bundles group related templates so a single command generates all the files at once. A Kubernetes app typically needs both a Deployment and a Service -- a natural bundle.

Each bundle lives in bundles/{name}/{version}/ and includes a conjure.json that declares shared_variables (available to every template in the bundle) and template_variables (scoped to individual template files).

$ mkdir -p bundles/web-app/1.0.0$ cat > bundles/web-app/1.0.0/conjure.json << 'EOF'{  "schema_version": "v1",  "bundle_name": "web-app",  "bundle_type": "kubernetes",  "bundle_description": "Kubernetes Deployment and Service",  "shared_variables": [    {      "name": "app_name",      "description": "Application name",      "type": "string",      "default": ""    },    {      "name": "namespace",      "description": "Kubernetes namespace",      "type": "string",      "default": "default"    },    {      "name": "port",      "description": "Application port",      "type": "int",      "default": "8080"    }  ],  "template_variables": {    "deployment.yaml.tmpl": [      {        "name": "image",        "description": "Container image (e.g., nginx:latest)",        "type": "string",        "default": ""      },      {        "name": "replicas",        "description": "Number of pod replicas",        "type": "int",        "default": "2"      }    ],    "service.yaml.tmpl": [      {        "name": "service_type",        "description": "Service type (ClusterIP, LoadBalancer)",        "type": "string",        "default": "ClusterIP"      }    ]  }}EOF

Inspect the bundle metadata:

$ cat bundles/web-app/1.0.0/conjure.json{  "schema_version": "v1",  "bundle_name": "web-app",  "bundle_type": "kubernetes",  "bundle_description": "Kubernetes Deployment and Service",  "shared_variables": [    {      "name": "app_name",      "description": "Application name",      "type": "string",      "default": ""    },    {      "name": "namespace",      "description": "Kubernetes namespace",      "type": "string",      "default": "default"    },    {      "name": "port",      "description": "Application port",      "type": "int",      "default": "8080"    }  ],  "template_variables": {    "deployment.yaml.tmpl": [      {        "name": "image",        "description": "Container image (e.g., nginx:latest)",        "type": "string",        "default": ""      },      {        "name": "replicas",        "description": "Number of pod replicas",        "type": "int",        "default": "2"      }    ],    "service.yaml.tmpl": [      {        "name": "service_type",        "description": "Service type (ClusterIP, LoadBalancer)",        "type": "string",        "default": "ClusterIP"      }    ]  }}

Create the Deployment template:

$ cat > bundles/web-app/1.0.0/deployment.yaml.tmpl << 'EOF'apiVersion: apps/v1kind: Deploymentmetadata:  name: {{.app_name}}-deployment  namespace: {{.namespace}}spec:  replicas: {{.replicas}}  selector:    matchLabels:      app: {{.app_name}}  template:    metadata:      labels:        app: {{.app_name}}    spec:      containers:      - name: {{.app_name}}        image: {{.image}}        ports:        - containerPort: {{.port}}EOF

Inspect the Deployment template:

$ cat bundles/web-app/1.0.0/deployment.yaml.tmplapiVersion: apps/v1kind: Deploymentmetadata:  name: {{.app_name}}-deployment  namespace: {{.namespace}}spec:  replicas: {{.replicas}}  selector:    matchLabels:      app: {{.app_name}}  template:    metadata:      labels:        app: {{.app_name}}    spec:      containers:      - name: {{.app_name}}        image: {{.image}}        ports:        - containerPort: {{.port}}

Create the Service template:

$ cat > bundles/web-app/1.0.0/service.yaml.tmpl << 'EOF'apiVersion: v1kind: Servicemetadata:  name: {{.app_name}}-service  namespace: {{.namespace}}spec:  type: {{.service_type}}  selector:    app: {{.app_name}}  ports:  - port: 80    targetPort: {{.port}}EOF

Inspect the Service template:

$ cat bundles/web-app/1.0.0/service.yaml.tmplapiVersion: v1kind: Servicemetadata:  name: {{.app_name}}-service  namespace: {{.namespace}}spec:  type: {{.service_type}}  selector:    app: {{.app_name}}  ports:  - port: 80    targetPort: {{.port}}

Bundles: Generate Multiple Files at Once

With the bundle defined, create a values file for the production deployment:

$ cat > values/production.yaml << 'EOF'app_name: my-apinamespace: productionport: 8080image: my-api:1.0.0replicas: 3service_type: LoadBalancerEOF

Inspect the values file:

$ cat values/production.yamlapp_name: my-apinamespace: productionport: 8080image: my-api:1.0.0replicas: 3service_type: LoadBalancer

Confirm the bundle is registered:

$ conjure list bundlesAvailable Bundles:   web-app    Description: Kubernetes Deployment and Service    Type: kubernetes    Latest: 1.0.0 Total: 1 bundle

Generate both manifests with a single command:

$ conjure bundle web-app \    -f values/production.yaml \    -o ./manifests/Using bundle: web-app v1.0.0 (source: local)Description: Kubernetes Deployment and ServiceType: kubernetes   ✓ Rendered: deployment.yaml  ✓ Rendered: service.yaml ✓ Bundle rendered successfully✓ 2 files written to: ./manifests/

Inspect the generated manifests:

$ ls ./manifests/deployment.yaml  service.yaml
$ cat ./manifests/deployment.yamlapiVersion: apps/v1kind: Deploymentmetadata:  name: my-api-deployment  namespace: productionspec:  replicas: 3  selector:    matchLabels:      app: my-api  template:    metadata:      labels:        app: my-api    spec:      containers:      - name: my-api        image: my-api:1.0.0        ports:        - containerPort: 8080

Remote Repositories

Host templates on any HTTPS server with a valid index.json manifest.

Use conjure repo index to generate the manifest from your local templates and bundles and then host them centrally for everyone to access.

Configure both a local and remote repository and define priority.

$ cat > conjure.yaml << EOFtemplates_source: bothbundles_source: bothtemplates_local_dir: $PWDbundles_local_dir: $PWDtemplates_remote_url: https://raw.githubusercontent.com/WizardOpsTech/conjure-get-started/masterbundles_remote_url: https://raw.githubusercontent.com/WizardOpsTech/conjure-get-started/mastertemplates_priority: local-firstbundles_priority: local-firstEOF $ conjure list templatesAvailable Templates:   systemd-service    Description: Linux systemd service unit file    Type: system    Latest: 1.0.0   terraform-aws-ec2    Description: Terraform configuration for AWS EC2 instance    Type: terraform    Latest: 1.0.0   terraform-azure-vm    Description: Terraform configuration for Azure Virtual Machine    Type: terraform    Latest: 1.0.0   terraform-gcp-vm    Description: Terraform configuration for GCP Compute Engine instance    Type: terraform    Latest: 1.0.0 Total: 4 templates

What Can You Templatize?

Anything text-based: Kubernetes manifests, Terraform modules, GitHub Actions workflows, application configs (JSON, YAML, TOML), API payloads, documentation scaffolds. If your team writes it by hand and it follows a pattern, Conjure can generate it.

Get Started

Install Conjure, create your first template, and start generating. Full documentation at conjure.wizardops.dev.