Cosmic tool for provisioning and managing infrastructure.
Comet is a command-line interface (CLI) tool designed to streamline infrastructure provisioning and management. It provides a unified interface for handling infrastructure operations with modern tooling and practices.
- 🚀 JavaScript Configuration - Define infrastructure using a familiar, powerful programming language instead of limited HCL
- ✨ Modern DSL Enhancements - Bulk environment variables and secrets shorthand reduce boilerplate by ~30%
- �️ Build Your Own Abstractions - It's JavaScript! Create your own helper functions for domains, components, tags, etc.
- �🔄 Automatic Backend Generation - Comet generates
backend.tf.json
files automatically based on your stack configuration - 🔗 Cross-Stack References - Simple
state()
template function to reference outputs from other stacks - 🔐 Built-in Secrets Management - Native SOPS integration for encrypted secrets in your configurations
- 📦 Component Reusability - Define components once, reuse across environments with different configurations
- 🎯 Multi-Environment Support - Manage dev, staging, production, and any other environments from a single codebase
- ⚡ Terraform/OpenTofu Integration - Works seamlessly with both Terraform and OpenTofu
- �️ Minimal & Unopinionated - Provides universal primitives, you build team-specific patterns
- 📝 YAML Configuration - Simple
comet.yaml
for project-level settings - 🌟 Template Support - Use Go templates in component configurations for dynamic values
Comet fills the gap between plain Terraform/OpenTofu and heavy enterprise frameworks, offering a pragmatic solution for teams that need DRY infrastructure configurations without the overhead of complex tooling.
While Terraform/OpenTofu are powerful, they have limitations when managing multi-environment infrastructures:
- ❌ Backend configuration cannot be dynamic - You must use partial configuration or wrappers
- ❌ No native multi-environment patterns - Workspaces aren't suitable for production isolation
- ❌ Verbose .tfvars management - Maintaining separate variable files for each environment
- ❌ Complex cross-stack references - Manual remote state data source configuration
- ❌ Limited DRY capabilities - HCL's declarative nature makes abstraction difficult
Comet provides:
- ✅ JavaScript-based configuration - Leverage a familiar, powerful language for infrastructure config
- ✅ Automatic backend generation - No more manual backend.tf files
- ✅ Built-in cross-stack references - Simple
state()
function for referencing other stacks - ✅ SOPS integration - Native encrypted secrets support
- ✅ Clean component reuse - Share modules across environments with ease
- ✅ Minimal abstraction - Thin wrapper that doesn't hide Terraform/OpenTofu
Feature | Comet | Terragrunt | Atmos | Plain OpenTofu |
---|---|---|---|---|
Config Language | JavaScript ✨ | HCL + YAML | YAML 📄 | HCL |
Learning Curve | Moderate | Moderate | Steep | Low |
Backend Config | ✅ Auto-generated | ✅ Native | ✅ Native | ❌ Manual |
Cross-Stack Refs | ✅ state() function |
✅ Dependencies | ✅ Remote state | |
Module Reuse | ✅ JavaScript logic | ✅ Dependencies | ✅ Imports/Mixins | |
Secrets Management | ✅ SOPS built-in | ❌ Bring your own | ❌ Bring your own | ❌ Manual |
Templating | ✅ JS template literals | ❌ Limited | ||
Community Size | Small 🐭 | Large 🐘 | Medium 🐈 | Huge 🦕 |
Maturity | Young | Very Mature | Mature | Stable |
Opinionation | Low | Medium | Very High | Minimal |
Enterprise Features | ❌ | ✅ | ✅✅✅ | ❌ |
Vendor Lock-in | None | None | Cloud Posse | None |
Ideal For | Small-Medium teams | Most teams | Large enterprises | Simple setups |
Choose Comet if:
- ✅ You have < 50 components across multiple environments
- ✅ Your team prefers JavaScript over YAML/HCL
- ✅ You want minimal abstraction and transparency
- ✅ You value simplicity over extensive features
- ✅ You need built-in secrets management (SOPS)
- ✅ You're comfortable maintaining a custom tool
Consider alternatives if:
⚠️ You need enterprise governance features (policy enforcement, compliance)⚠️ You have 100+ components across multiple orgs/regions⚠️ You want the most battle-tested solution (Terragrunt)⚠️ You need Cloud Posse's reference architectures (Atmos)
- Go 1.23 or later
git clone https://github.com/moonwalker/comet.git
cd comet
go build
Important: Comet's DSL is a superset of JavaScript. You can create any helper functions, abstractions, or patterns you need - you're not limited to built-in features!
👉 Read: It's Just JavaScript! - Learn how to build your own domain helpers, component factories, and more.
comet [command] [flags]
--config
- Specify config file (default:comet.yaml
)--dir
- Specify stacks directory (default:stacks
)
For detailed command documentation, use:
comet --help
Description: Print the version.
Usage:
comet version
Description: Show changes required by the current configuration.
Usage:
comet plan <stack> [component]
Description: Initialize backends and providers without running plan/apply operations.
Usage:
comet init <stack> [component]
Useful for:
- Preparing infrastructure for read-only operations (like
comet output
) - Troubleshooting provider/backend initialization issues
- CI/CD validation pipelines
Description: Show output values from components.
Usage:
comet output <stack> [component]
Description: List stacks or components.
Usage:
comet list [stack]
Description: Generate TypeScript definitions for IDE support.
Usage:
comet types
Generates index.d.ts
in your stacks directory, providing autocomplete and type hints when editing stack files in your IDE. Add /// <reference path="./index.d.ts" />
to your stack files to enable IDE support.
Description: Destroy previously-created infrastructure.
Usage:
comet destroy <stack> [component]
Description: Delete Terraform-related folders and files.
Usage:
comet clean <stack> [component]
Description: Create or update infrastructure.
Usage:
comet apply <stack> [component]
Description: Export stack to standalone Terraform files.
Usage:
comet export <stack> [component] -o <output-dir>
// stacks/shared.js
const settings = {
project_name: 'myapp',
domain: 'example.com',
gcp_project: 'my-gcp-project'
}
module.exports = { settings }
// stacks/production.js
const { settings } = require('./shared.js')
stack('production', { settings })
backend('gcs', {
bucket: 'my-terraform-state',
prefix: `${settings.project_name}/{{ .stack }}/{{ .component }}`
})
const vpc = component('vpc', 'modules/vpc', {
cidr_block: '10.0.0.0/16',
region: 'us-central1'
})
const gke = component('gke', 'modules/gke', {
network: vpc.id,
cluster_name: `${settings.project_name}-prod`
})
Reference outputs from other stacks:
// stacks/application.js
const webapp = component('webapp', 'modules/k8s-app', {
// Reference infrastructure stack outputs
cluster_endpoint: '{{ (state "infrastructure" "gke").endpoint }}',
vpc_id: '{{ (state "infrastructure" "vpc").id }}'
})
// Automatically generate provider configurations
append('providers', [
`provider "google" {`,
` project = "${settings.gcp_project}"`,
` region = "us-central1"`,
`}`
])
Comet provides built-in SOPS integration with convenient shorthand syntax:
// Configure secrets defaults (optional)
secretsConfig({
defaultProvider: 'sops',
defaultPath: 'secrets.enc.yaml'
})
// Old verbose syntax (still works)
const db1 = component('database', 'modules/cloudsql', {
password: secrets('sops://secrets.enc.yaml#/database/password'),
admin_user: secrets('sops://secrets.enc.yaml#/database/admin_user')
})
// New shorthand - much cleaner!
const db2 = component('database', 'modules/cloudsql', {
password: secret('database/password'), // or secret('database.password')
admin_user: secret('database.admin_user')
})
Comet includes productivity features that reduce boilerplate by ~30%:
Bulk Environment Variables:
// Set multiple environment variables at once
envs({
AWS_ACCESS_KEY_ID: secret('aws/access_key'),
AWS_SECRET_ACCESS_KEY: secret('aws/secret_key'),
CLOUDFLARE_API_TOKEN: secret('cloudflare/token')
})
Build Your Own Abstractions:
Since Comet's DSL is JavaScript, you can create any helper functions you need for your team's patterns:
const opts = { domain: 'example.io' }
// Your own domain helpers
const subdomain = (name) => `${name}.{{ .stack }}.${opts.domain}`
const fqdn = (name) => `${name}.${opts.domain}`
// Your own component factories
function k8sApp(name, config) {
return component(name, 'modules/k8s-app', {
namespace: 'default',
replicas: 2,
domain: subdomain(name),
...config
})
}
// Your own credential presets
function setupAWS() {
envs({
AWS_ACCESS_KEY_ID: secret('aws/access_key'),
AWS_SECRET_ACCESS_KEY: secret('aws/secret_key'),
AWS_REGION: 'us-east-1'
})
}
// Use them!
setupAWS()
const api = k8sApp('api', {
replicas: 3,
database_url: db.connection_string
})
Comet stays minimal and unopinionated. You build exactly what you need.
See DSL Improvements and Userland Patterns for complete documentation.
For more examples, see the docs directory.
Comet can be configured using comet.yaml
in your project directory.
# comet.yaml
stacks_dir: stacks # Directory containing stack files
work_dir: stacks/_components # Working directory for components
generate_backend: false # Auto-generate backend.tf.json
log_level: INFO # Log verbosity
tf_command: tofu # Use 'tofu' or 'terraform'
Set plain environment variables that are loaded before commands run:
# comet.yaml
env:
TF_LOG: DEBUG
AWS_REGION: us-west-2
PROJECT_ID: my-project
Features:
- Plain values only (fast startup)
- Shell environment variables take precedence
- Loaded before stack parsing begins
Note: The env
section only supports plain values. For secrets, use the bootstrap
feature below.
Bootstrap fetches secrets from 1Password/SOPS and caches them locally. Run once, then all commands are fast!
# comet.yaml
bootstrap:
- name: sops-age-key
type: secret
source: op://vault/infrastructure/sops-age-key # Your 1Password path
target: ~/.config/sops/age/keys.txt
mode: "0600"
Usage:
# One-time setup (takes ~4s)
comet bootstrap
# Check status
comet bootstrap status
# Now all commands are fast!
comet plan dev # 100ms instead of 4s!
comet apply dev
Features:
- ✅ One-time cost - Slow fetch only happens once
- ✅ Fast commands - All subsequent commands use cached secrets
- ✅ Idempotent - Safe to run multiple times
- ✅ State tracking - Knows what's been set up
- ✅ Standard location - Uses SOPS's default key path
Bootstrap Types:
bootstrap:
# Fetch and cache secrets
- name: sops-key
type: secret
source: op://vault/item/field
target: ~/.config/sops/age/keys.txt
mode: "0600"
# Check required tools exist
- name: check-tools
type: check
command: op,sops,tofu # Comma-separated
# Run custom commands
- name: gcloud-auth
type: command
command: gcloud auth application-default login
optional: true
Migrating from v0.5.0:
If you were using op://
or sops://
in the env
section, migrate to bootstrap
:
# OLD (v0.5.0) - Slow on every command
env:
SOPS_AGE_KEY: op://vault/key/private
# NEW (v0.6.0) - Fast after bootstrap
bootstrap:
- name: sops-key
type: secret
source: op://vault/key/private
target: ~/.config/sops/age/keys.txt
mode: "0600"
Recommended approach for frequently-used secrets:
# Set in your shell (one-time cost)
export SOPS_AGE_KEY=$(op read "op://ci-cd/sops-age-key/private")
# Or add to ~/.bashrc, ~/.zshrc, ~/.config/fish/config.fish, etc.
Only use secret references in comet.yaml
for:
- Secrets that change frequently
- CI/CD environments where shell setup is inconvenient
- Situations where the ~3-5s overhead is acceptable
See Best Practices for more configuration examples.
- Go 1.23+
- Clone the repository
git clone https://github.com/moonwalker/comet.git
- Build the project
go build
Contributions are welcome! Please feel free to submit a Pull Request.
This project is licensed under the terms specified in the project's license file.