# Nickel Configuration Examples

Type-safe infrastructure configuration patterns using Nickel as the source of truth.

## Basic Server Configuration

Simple type-safe server definition:

```nickel
let Server = {
  name | String,
  provider | String,
  instance_type | String,
  cpu | Number,
  memory | Number,
  disk_size | Number,
  image | String,
  tags | Array String,
  ?backup | Bool,
}

{
  servers = [
    {
      name = "web-01",
      provider = "aws",
      instance_type = "t3.large",
      cpu = 2,
      memory = 4,
      disk_size = 50,
      image = "ubuntu-22.04",
      tags = ["web", "frontend", "prod"],
      backup = true
    }
  ]
}
```

## Hierarchical Configuration

Merge base with environment-specific overrides:

```nickel
# base-config.ncl
{
  app_name = "my-app",
  version = "1.0.0",

  database = {
    engine = "postgres",
    version = "15",
    max_connections = 100,
    backup_retention_days = 7
  },

  servers = {
    cpu = 2,
    memory = 4,
    count = 3
  }
}
```

```nickel
# prod-config.ncl - Override for production
let base = import "base-config.ncl"

base
| > {
  servers = {
    cpu = 4,
    memory = 8,
    count = 5
  },

  database = {
    max_connections = 500,
    backup_retention_days = 30,
    multi_az = true
  }
}
```

## Schema Validation

Define and enforce schemas:

```nickel
# schemas/deployment-schema.ncl
{
  # Infrastructure must have workspace, environment, and resources
  workspace | String,
  environment | String,

  resources = {
    servers | Array,
    databases | Array,
    load_balancers | Array,
  },

  # Constraints
  metadata | {
    owner | String,
    cost_center | String,
    compliance_tags | Array String
  },

  # Optional fields with defaults
  ?enable_monitoring | Bool,
  ?backup_enabled | Bool,
  ?auto_scaling | Bool
}
```

Validate against schema:

```nickel
# deployment.ncl
let schema = import "schemas/deployment-schema.ncl"

# This config must match schema or compilation fails
let config = {
  workspace = "production",
  environment = "prod",

  resources = {
    servers = [{
      name = "web-01",
      cpu = 4,
      memory = 8
    }],
    databases = [{
      name = "primary-db",
      engine = "postgres"
    }],
    load_balancers = [{
      name = "main-lb",
      type = "round-robin"
    }]
  },

  metadata = {
    owner = "platform-team",
    cost_center = "engineering",
    compliance_tags = ["pci-dss", "hipaa"]
  },

  enable_monitoring = true,
  backup_enabled = true
}

config | schema
```

## Conditional Configuration

Type-safe conditional logic:

```nickel
let environment = "production"

let config = {
  database = {
    engine = "postgres",
    version = if environment == "production" then "15" else "14",
    replicas = if environment == "production" then 3 else 1,
    backup_retention = if environment == "production" then 30 else 7,
    multi_az = environment == "production"
  },

  servers = {
    count = if environment == "production" then 5 else 2,
    cpu = if environment == "production" then 4 else 2,
    memory = if environment == "production" then 8 else 4,
    instance_type =
      if environment == "production" then "large" else "small"
  }
}

config
```

## Function-based Configuration

Reusable configuration builders:

```nickel
# Define reusable server factory
let create_server = fun name provider cpu memory =>
  {
    name = name,
    provider = provider,
    cpu = cpu,
    memory = memory,
    disk_size = 100,
    backup = true,
    monitoring = true
  }

# Define reusable database factory
let create_database = fun engine version replicas =>
  {
    engine = engine,
    version = version,
    replicas = replicas,
    max_connections = 200,
    backup_enabled = true,
    encryption = "aes-256"
  }

# Use factories
{
  servers = [
    create_server "web-01" "aws" 4 8,
    create_server "web-02" "aws" 4 8,
    create_server "api-01" "upcloud" 8 16
  ],

  databases = [
    create_database "postgres" "15" 3,
    create_database "mysql" "8.0" 2
  ]
}
```

## Multi-Cloud Configuration

Define infrastructure across providers:

```nickel
# multi-cloud.ncl
let providers = {
  aws = {
    region = "us-east-1",
    credentials = {
      access_key = "\${AWS_ACCESS_KEY}",
      secret_key = "\${AWS_SECRET_KEY}"
    }
  },
  upcloud = {
    region = "us-sjc",
    credentials = {
      username = "\${UPCLOUD_USER}",
      api_token = "\${UPCLOUD_TOKEN}"
    }
  },
  hetzner = {
    location = "fsn1",
    credentials = {
      api_token = "\${HETZNER_TOKEN}"
    }
  }
}

{
  infrastructure = {
    web_tier = {
      provider = "aws",
      servers = [
        {
          name = "web-01",
          instance_type = "t3.large",
          count = 3
        }
      ]
    },

    api_tier = {
      provider = "upcloud",
      servers = [
        {
          name = "api-01",
          plan = "4xCPU-8GB",
          count = 2
        }
      ]
    },

    database_tier = {
      provider = "hetzner",
      servers = [
        {
          name = "db-01",
          server_type = "cx21",
          count = 1
        }
      ]
    }
  }
}
```

## Variable Interpolation

Dynamic configuration from environment:

```nickel
# Load from environment variables
let env = {
  workspace = std.get_env "PROVISIONING_WORKSPACE",
  environment = std.get_env "ENVIRONMENT" | | "development",
  region = std.get_env "AWS_REGION" | | "us-east-1",
  version = std.get_env "APP_VERSION" | | "latest"
}

{
  workspace = env.workspace,
  environment = env.environment,

  app = {
    name = "my-app",
    version = env.version,
    image = "myregistry/my-app:\(env.version)"
  },

  infrastructure = {
    region = env.region,
    servers = {
      count = if env.environment == "production" then 5 else 2,
      instance_type =
        if env.environment == "production" then "large" else "small"
    }
  }
}
```

## Record Merging

Combine configurations safely:

```nickel
# Base configuration
let base = {
  app_name = "web-app",
  database = {
    engine = "postgres",
    version = "15"
  },
  servers = {
    cpu = 2,
    memory = 4
  }
}

# Environment override (only replaces specified fields)
let prod_override = {
  database = {
    version = "15.2",
    replicas = 3
  },
  servers = {
    cpu = 4,
    memory = 8,
    count = 5
  }
}

# Merge: base gets updated with prod_override values
base & prod_override
```

## Array Processing

Build complex array structures:

```nickel
let create_server_with_tags = fun i name =>
  {
    name = "\(name)-\(| i std.to_string)",
    cpu = 4,
    memory = 8,
    tags = [
      "managed-by=provisioning",
      "tier=web",
      "index=\(| i std.to_string)"
    ]
  }

# Generate 5 servers
{
  servers = [
    create_server_with_tags 0 "web",
    create_server_with_tags 1 "web",
    create_server_with_tags 2 "web",
    create_server_with_tags 3 "web",
    create_server_with_tags 4 "web"
  ]
}
```

## Comments and Documentation

Self-documenting configuration:

```nickel
{
  # Application metadata
  workspace = "production",
  environment = "prod",

  # Database configuration - multi-AZ PostgreSQL
  # Replicated across 3 availability zones for HA
  database = {
    engine = "postgres",
    version = "15",
    replicas = 3 | std.type.number,  # Type annotation: must be number
    max_connections = 500,
    # Backup retention: 30 days for compliance (PCI-DSS)
    backup_retention_days = 30
  },

  # Web server tier
  # Scaled for production load (estimated 10K req/sec)
  servers = {
    count = 5,
    cpu = 4,
    memory = 8,
    # Instance type from AWS t3 family
    instance_type = "t3.large"
  }
}
```

## Error Handling with Types

Type-safe configuration with validation:

```nickel
# Define valid values using types
let Database_Engine = [
  "postgres",
  "mysql",
  "mariadb"
]

let Instance_Type = [
  "small",
  "medium",
  "large",
  "xlarge"
]

{
  database = {
    engine | Engine_Engine = "postgres",  # Must be in allowed list
    replicas | Number & (std.number.Integer) = 3  # Must be integer
  },

  servers = {
    instance_type | Instance_Type = "large",  # Validated
    count | Number & (fun x => x > 0) = 5  # Must be positive
  }
}
```

## Real-World Example

Complete production-grade configuration:

```nickel
# production-infrastructure.ncl
{
  # Core metadata
  workspace = "production",
  environment = "prod",
  owner = "platform-team",
  cost_center = "engineering",

  # Database tier
  database = {
    engine = "postgres",
    version = "15.2",
    instance_class = "db.r6i.2xlarge",
    replicas = 3,
    multi_az = true,
    backup_retention_days = 30,
    encryption = {
      at_rest = "aes-256",
      in_transit = "tls-1.3"
    }
  },

  # Cache layer
  cache = {
    engine = "redis",
    version = "7.0",
    node_type = "cache.r6g.xlarge",
    num_cache_clusters = 3,
    automatic_failover = true
  },

  # Load balancer
  load_balancer = {
    type = "application",
    scheme = "internet-facing",
    health_check = {
      protocol = "HTTP",
      path = "/health",
      interval = 30,
      timeout = 5,
      healthy_threshold = 2,
      unhealthy_threshold = 3
    }
  },

  # Web servers
  servers = {
    count = 5,
    instance_type = "t3.large",
    cpu = 2,
    memory = 8,
    disk_size = 100,
    monitoring = {
      enabled = true,
      metrics = ["cpu", "memory", "disk", "network"]
    },
    logging = {
      enabled = true,
      retention_days = 30
    }
  }
}
```

## Related Documentation

- [Nickel Guide](../infrastructure/nickel-guide.md)
- [Configuration System](../infrastructure/configuration-system.md)
- [Schemas Reference](../infrastructure/schemas-reference.md)
