
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.
You'll need curl and a Unix-like shell (Linux or macOS).
Run the one-liner for your platform. The script detects your OS and architecture automatically.
$ curl -sfL https://raw.githubusercontent.com/WizardOpsTech/conjure/main/install.sh | sh$ irm https://raw.githubusercontent.com/WizardOpsTech/conjure/main/install.ps1 | iexThen verify the install:
$ conjure --versionconjure version 1.0.0
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
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.
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.
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
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
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}}
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
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
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.
Install Conjure, create your first template, and start generating. Full documentation at conjure.wizardops.dev.