Configuration
Learn how to configure cuenv for your projects using CUE’s powerful constraint-based configuration language.
Configuration Files
Section titled “Configuration Files”cuenv uses CUE files for configuration, following a hierarchical structure that allows for composition and inheritance.
Configuration Layout
Section titled “Configuration Layout”cuenv evaluates the CUE package you point it at (by default the cuenv package in the current directory). Every .cue file that belongs to that package participates automatically—there is no fixed file ordering or special filename.
Common organization patterns include:
- Keeping an
env.cueentry point that importsschema.#Cuenv - Splitting large sections into files such as
tasks.cueor directories like.cuenv/ - Importing shared packages from elsewhere in your CUE module (for example
import "github.com/myorg/common")
Basic Structure
Section titled “Basic Structure”package cuenv
import "github.com/cuenv/cuenv/schema"
schema.#Cuenv
// Environment variablesenv: { NODE_ENV: "development" | "production" PORT: 8080 LOG_LEVEL: "info"}
// Task definitionstasks: { build: { description: "Build the project" command: "bun" args: ["run", "build"] dependsOn: ["install"] }
install: { description: "Install dependencies" command: "bun" args: ["install"] }}Environment Configuration
Section titled “Environment Configuration”Basic Environments
Section titled “Basic Environments”Define environment variables with type constraints:
env: { // String variables NODE_ENV: "development" | "staging" | "production" SERVICE_NAME: string & =~"^[a-zA-Z][a-zA-Z0-9-]*$"
// Numeric variables (CUE treats environment variables as strings, so conversion might be needed or validation logic adjusted) // Typically env vars are strings: PORT: string & =~"^[0-9]+$" WORKER_COUNT: string | *"4"
// Boolean variables (as strings) DEBUG: "true" | "false" | *"false" ENABLE_METRICS: "true" | "false" | *"true"}Environment Composition
Section titled “Environment Composition”Compose environments from multiple sources:
// Base environment#BaseEnv: { LOG_LEVEL: "info" | "debug" | "warn" | "error" SERVICE_NAME: string}
// Development environment// In cuenv, you typically use a single `env` block with conditional logic or unified types// But you can define specialized structs:development: #BaseEnv & { LOG_LEVEL: "debug" DEBUG: "true" DATABASE_URL: "postgresql://localhost/myapp_dev"}Conditional Configuration
Section titled “Conditional Configuration”Use CUE’s conditional logic for dynamic configuration:
package cuenv
// Configuration based on environmentlet env = "development" // or from external source
if env == "development" { database: { host: "localhost" port: 5432 }}Task Configuration
Section titled “Task Configuration”Basic Tasks
Section titled “Basic Tasks”tasks: { test: { description: "Run tests" command: "cargo" args: ["test"] env: { RUST_LOG: "debug" } }
lint: { description: "Run linter" command: "cargo" args: ["clippy", "--", "-D", "warnings"] }
build: { description: "Build project" command: "cargo" args: ["build", "--release"] dependsOn: ["lint", "test"] }}Task Dependencies
Section titled “Task Dependencies”Define complex dependency graphs:
tasks: { // Parallel tasks (no dependencies) "lint:rust": { command: "cargo" args: ["clippy"] }
"lint:js": { command: "eslint" args: ["."] }
// Sequential dependency test: { command: "cargo" args: ["test"] dependsOn: ["lint:rust", "lint:js"] // Waits for both }}Task Environment Inheritance
Section titled “Task Environment Inheritance”// Shared task environment#TaskEnv: { RUST_LOG: "info" PATH: "$PATH:/usr/local/bin"}
tasks: { build: #TaskEnv & { command: "cargo build" environment: { CARGO_TARGET_DIR: "target" } }
test: #TaskEnv & { command: "cargo test" environment: { RUST_LOG: "debug" // Override shared value } }}Schema Definitions
Section titled “Schema Definitions”Custom Schemas
Section titled “Custom Schemas”Define reusable configuration schemas:
// Schema definitions#DatabaseConfig: { host: string port: int & >0 & <65536 database: string username: string password: string // Should be loaded from secrets ssl: bool | *true}
#ServiceConfig: { name: string & =~"^[a-zA-Z][a-zA-Z0-9-]*$" port: int & >1024 replicas: int & >0 | *3 environment: [string]: string | number | bool database: #DatabaseConfig}
// Apply schema to configurationservice: #ServiceConfig & { name: "api-server" port: 8080 database: { host: "postgres.local" port: 5432 database: "myapp" username: "app_user" password: "$DATABASE_PASSWORD" // From secret }}Validation Rules
Section titled “Validation Rules”Add custom validation constraints:
#Config: { // Version must follow semantic versioning version: string & =~"^[0-9]+\\.[0-9]+\\.[0-9]+$"
// Port must be available (runtime check) port: int & >1024 & <65536
// Environment must be valid env: "development" | "staging" | "production"
// Features can only be enabled in certain environments if env == "production" { debug: false profiling: false }}Secret Management
Section titled “Secret Management”Secret References
Section titled “Secret References”cuenv uses exec-based secret resolvers. Reference external secrets using the built-in types:
package cuenv
import "github.com/cuenv/cuenv/schema"
schema.#Cuenv
env: { // 1Password secret reference DATABASE_PASSWORD: schema.#OnePasswordRef & { ref: "op://vault-name/item-name/password" }
// GCP Secret Manager API_KEY: schema.#GcpSecret & { project: "my-gcp-project" secret: "api-key" }
// Custom exec-based resolver CUSTOM_SECRET: schema.#Secret & { command: "my-secret-tool" args: ["get", "my-secret"] }}See the Secrets documentation for more details on secret providers.
Advanced Features
Section titled “Advanced Features”Modular Configuration
Section titled “Modular Configuration”Split configuration across multiple files:
cuenv.cue
package config
import ( "github.com/myorg/myproject/environments" "github.com/myorg/myproject/tasks")
project: { name: "myproject" version: "1.0.0"}
// Include other modulesenvironment: environments.developmenttasks: tasks.commonenvironments/development.cue
package environments
development: { NODE_ENV: "development" DEBUG: true DATABASE_URL: "postgresql://localhost/myapp_dev"}Template Functions
Section titled “Template Functions”Use CUE’s built-in functions for dynamic values:
import "strings"
config: { // String manipulation serviceName: strings.ToLower("My-Service-Name") // "my-service-name"
// Environment-based configuration logLevel: { if environment.DEBUG { "debug" } if !environment.DEBUG { "info" } }
// Computed values serverAddress: "http://localhost:\(environment.PORT)"}Configuration Validation
Section titled “Configuration Validation”Built-in Validation
Section titled “Built-in Validation”cuenv automatically validates configuration against schemas when tasks are run.
# Check environment validitycuenv env checkCustom Validators
Section titled “Custom Validators”Extend validation with custom rules:
#Validators: { // Port availability check portAvailable: { field: "port" check: "network.portAvailable" message: "Port {value} is not available" }
// Database connectivity databaseReachable: { field: "database.host" check: "network.tcpConnect" message: "Cannot connect to database at {value}" }}Best Practices
Section titled “Best Practices”Organization
Section titled “Organization”- Keep configuration files small and focused
- Use meaningful names for fields and values
- Group related configuration together
- Document complex constraints with comments
Security
Section titled “Security”- Never commit secrets to version control
- Use secret references instead of plain text values
- Validate secret access patterns
- Rotate secrets regularly
Maintainability
Section titled “Maintainability”- Use schemas to enforce consistency
- Leverage CUE’s composition features
- Keep environment differences minimal
- Test configuration changes
See Also
Section titled “See Also”- Typed Environments - Environment management patterns
- Task Orchestration - Task definition and execution
- Secret Management - Secure secret handling
- Examples - Common configuration patterns