# Nickel Executable Examples & Test Cases\n\n**Status**: Practical Developer Guide\n**Last Updated**: 2025-12-15\n**Purpose**: Copy-paste ready examples, validatable patterns, runnable test cases\n\n---\n\n## Setup: Run Examples Locally\n\n### Prerequisites\n\n```\n# Install Nickel\nbrew install nickel\n# or from source: https://nickel-lang.org/getting-started/\n\n# Verify installation\nnickel --version  # Should be 1.0+\n```\n\n### Directory Structure for Examples\n\n```\nmkdir -p ~/nickel-examples/{simple,complex,production}\ncd ~/nickel-examples\n```\n\n---\n\n## Example 1: Simple Server Configuration (Executable)\n\n### Step 1: Create Contract File\n\n```\ncat > simple/server_contracts.ncl << 'EOF'\n{\n  ServerConfig = {\n    name | String,\n    cpu_cores | Number,\n    memory_gb | Number,\n    zone | String,\n  },\n}\nEOF\n```\n\n### Step 2: Create Defaults File\n\n```\ncat > simple/server_defaults.ncl << 'EOF'\n{\n  web_server = {\n    name = "web-01",\n    cpu_cores = 4,\n    memory_gb = 8,\n    zone = "us-nyc1",\n  },\n\n  database_server = {\n    name = "db-01",\n    cpu_cores = 8,\n    memory_gb = 16,\n    zone = "us-nyc1",\n  },\n\n  cache_server = {\n    name = "cache-01",\n    cpu_cores = 2,\n    memory_gb = 4,\n    zone = "us-nyc1",\n  },\n}\nEOF\n```\n\n### Step 3: Create Main Module with Hybrid Interface\n\n```\ncat > simple/server.ncl << 'EOF'\nlet contracts = import "./server_contracts.ncl" in\nlet defaults = import "./server_defaults.ncl" in\n\n{\n  defaults = defaults,\n\n  # Level 1: Maker functions (90% of use cases)\n  make_server | not_exported = fun overrides =>\n    let base = defaults.web_server in\n    base & overrides,\n\n  # Level 2: Pre-built instances (inspection/reference)\n  DefaultWebServer = defaults.web_server,\n  DefaultDatabaseServer = defaults.database_server,\n  DefaultCacheServer = defaults.cache_server,\n\n  # Level 3: Custom combinations\n  production_web_server = defaults.web_server & {\n    cpu_cores = 8,\n    memory_gb = 16,\n  },\n\n  production_database_stack = [\n    defaults.database_server & { name = "db-01", zone = "us-nyc1" },\n    defaults.database_server & { name = "db-02", zone = "eu-fra1" },\n  ],\n}\nEOF\n```\n\n### Test: Export and Validate JSON\n\n```\ncd simple/\n\n# Export to JSON\nnickel export server.ncl --format json | jq .\n\n# Expected output:\n# {\n#   "defaults": { ... },\n#   "DefaultWebServer": { "name": "web-01", "cpu_cores": 4, ... },\n#   "DefaultDatabaseServer": { ... },\n#   "DefaultCacheServer": { ... },\n#   "production_web_server": { "name": "web-01", "cpu_cores": 8, ... },\n#   "production_database_stack": [ ... ]\n# }\n\n# Verify specific fields\nnickel export server.ncl --format json | jq '.production_web_server.cpu_cores'\n# Output: 8\n```\n\n### Usage in Consumer Module\n\n```\ncat > simple/consumer.ncl << 'EOF'\nlet server = import "./server.ncl" in\n\n{\n  # Use maker function\n  staging_web = server.make_server {\n    name = "staging-web",\n    zone = "eu-fra1",\n  },\n\n  # Reference defaults\n  default_db = server.DefaultDatabaseServer,\n\n  # Use pre-built\n  production_stack = server.production_database_stack,\n}\nEOF\n\n# Export and verify\nnickel export consumer.ncl --format json | jq '.staging_web'\n```\n\n---\n\n## Example 2: Complex Provider Extension (Production Pattern)\n\n### Create Provider Structure\n\n```\nmkdir -p complex/upcloud/{contracts,defaults,main}\ncd complex/upcloud\n```\n\n### Provider Contracts\n\n```\ncat > upcloud_contracts.ncl << 'EOF'\n{\n  StorageBackup = {\n    backup_id | String,\n    frequency | String,\n    retention_days | Number,\n  },\n\n  ServerConfig = {\n    name | String,\n    plan | String,\n    zone | String,\n    backups | Array,\n  },\n\n  ProviderConfig = {\n    api_key | String,\n    api_password | String,\n    servers | Array,\n  },\n}\nEOF\n```\n\n### Provider Defaults\n\n```\ncat > upcloud_defaults.ncl << 'EOF'\n{\n  backup = {\n    backup_id = "",\n    frequency = "daily",\n    retention_days = 7,\n  },\n\n  server = {\n    name = "",\n    plan = "1xCPU-1 GB",\n    zone = "us-nyc1",\n    backups = [],\n  },\n\n  provider = {\n    api_key = "",\n    api_password = "",\n    servers = [],\n  },\n}\nEOF\n```\n\n### Provider Main Module\n\n```\ncat > upcloud_main.ncl << 'EOF'\nlet contracts = import "./upcloud_contracts.ncl" in\nlet defaults = import "./upcloud_defaults.ncl" in\n\n{\n  defaults = defaults,\n\n  # Makers (90% use case)\n  make_backup | not_exported = fun overrides =>\n    defaults.backup & overrides,\n\n  make_server | not_exported = fun overrides =>\n    defaults.server & overrides,\n\n  make_provider | not_exported = fun overrides =>\n    defaults.provider & overrides,\n\n  # Pre-built instances\n  DefaultBackup = defaults.backup,\n  DefaultServer = defaults.server,\n  DefaultProvider = defaults.provider,\n\n  # Production configs\n  production_high_availability = defaults.provider & {\n    servers = [\n      defaults.server & {\n        name = "web-01",\n        plan = "2xCPU-4 GB",\n        zone = "us-nyc1",\n        backups = [\n          defaults.backup & { frequency = "hourly" },\n        ],\n      },\n      defaults.server & {\n        name = "web-02",\n        plan = "2xCPU-4 GB",\n        zone = "eu-fra1",\n        backups = [\n          defaults.backup & { frequency = "hourly" },\n        ],\n      },\n      defaults.server & {\n        name = "db-01",\n        plan = "4xCPU-16 GB",\n        zone = "us-nyc1",\n        backups = [\n          defaults.backup & { frequency = "every-6h", retention_days = 30 },\n        ],\n      },\n    ],\n  },\n}\nEOF\n```\n\n### Test Provider Configuration\n\n```\n# Export provider config\nnickel export upcloud_main.ncl --format json | jq '.production_high_availability'\n\n# Export as TOML (for IaC config files)\nnickel export upcloud_main.ncl --format toml > upcloud.toml\ncat upcloud.toml\n\n# Count servers in production config\nnickel export upcloud_main.ncl --format json | jq '.production_high_availability.servers | length'\n# Output: 3\n```\n\n### Consumer Using Provider\n\n```\ncat > upcloud_consumer.ncl << 'EOF'\nlet upcloud = import "./upcloud_main.ncl" in\n\n{\n  # Simple production setup\n  simple_production = upcloud.make_provider {\n    api_key = "prod-key",\n    api_password = "prod-secret",\n    servers = [\n      upcloud.make_server { name = "web-01", plan = "2xCPU-4 GB" },\n      upcloud.make_server { name = "web-02", plan = "2xCPU-4 GB" },\n    ],\n  },\n\n  # Advanced HA setup with custom fields\n  ha_stack = upcloud.production_high_availability & {\n    api_key = "prod-key",\n    api_password = "prod-secret",\n    monitoring_enabled = true,\n    alerting_email = "ops@company.com",\n    custom_vpc_id = "vpc-prod-001",\n  },\n}\nEOF\n\n# Validate structure\nnickel export upcloud_consumer.ncl --format json | jq '.ha_stack | keys'\n```\n\n---\n\n## Example 3: Real-World Pattern - Taskserv Configuration\n\n### Taskserv Contracts (from wuji)\n\n```\ncat > production/taskserv_contracts.ncl << 'EOF'\n{\n  Dependency = {\n    name | String,\n    wait_for_health | Bool,\n  },\n\n  TaskServ = {\n    name | String,\n    version | String,\n    dependencies | Array,\n    enabled | Bool,\n  },\n}\nEOF\n```\n\n### Taskserv Defaults\n\n```\ncat > production/taskserv_defaults.ncl << 'EOF'\n{\n  kubernetes = {\n    name = "kubernetes",\n    version = "1.28.0",\n    enabled = true,\n    dependencies = [\n      { name = "containerd", wait_for_health = true },\n      { name = "etcd", wait_for_health = true },\n    ],\n  },\n\n  cilium = {\n    name = "cilium",\n    version = "1.14.0",\n    enabled = true,\n    dependencies = [\n      { name = "kubernetes", wait_for_health = true },\n    ],\n  },\n\n  containerd = {\n    name = "containerd",\n    version = "1.7.0",\n    enabled = true,\n    dependencies = [],\n  },\n\n  etcd = {\n    name = "etcd",\n    version = "3.5.0",\n    enabled = true,\n    dependencies = [],\n  },\n\n  postgres = {\n    name = "postgres",\n    version = "15.0",\n    enabled = true,\n    dependencies = [],\n  },\n\n  redis = {\n    name = "redis",\n    version = "7.0.0",\n    enabled = true,\n    dependencies = [],\n  },\n}\nEOF\n```\n\n### Taskserv Main\n\n```\ncat > production/taskserv.ncl << 'EOF'\nlet contracts = import "./taskserv_contracts.ncl" in\nlet defaults = import "./taskserv_defaults.ncl" in\n\n{\n  defaults = defaults,\n\n  make_taskserv | not_exported = fun overrides =>\n    defaults.kubernetes & overrides,\n\n  # Pre-built\n  DefaultKubernetes = defaults.kubernetes,\n  DefaultCilium = defaults.cilium,\n  DefaultContainerd = defaults.containerd,\n  DefaultEtcd = defaults.etcd,\n  DefaultPostgres = defaults.postgres,\n  DefaultRedis = defaults.redis,\n\n  # Wuji infrastructure (20 taskservs similar to actual)\n  wuji_k8s_stack = {\n    kubernetes = defaults.kubernetes,\n    cilium = defaults.cilium,\n    containerd = defaults.containerd,\n    etcd = defaults.etcd,\n  },\n\n  wuji_data_stack = {\n    postgres = defaults.postgres & { version = "15.3" },\n    redis = defaults.redis & { version = "7.2.0" },\n  },\n\n  # Staging with different versions\n  staging_stack = {\n    kubernetes = defaults.kubernetes & { version = "1.27.0" },\n    cilium = defaults.cilium & { version = "1.13.0" },\n    containerd = defaults.containerd & { version = "1.6.0" },\n    etcd = defaults.etcd & { version = "3.4.0" },\n    postgres = defaults.postgres & { version = "14.0" },\n  },\n}\nEOF\n```\n\n### Test Taskserv Setup\n\n```\n# Export stack\nnickel export taskserv.ncl --format json | jq '.wuji_k8s_stack | keys'\n# Output: ["kubernetes", "cilium", "containerd", "etcd"]\n\n# Get specific version\nnickel export taskserv.ncl --format json | \\n  jq '.staging_stack.kubernetes.version'\n# Output: "1.27.0"\n\n# Count taskservs in stacks\necho "Wuji K8S stack:"\nnickel export taskserv.ncl --format json | jq '.wuji_k8s_stack | length'\n\necho "Staging stack:"\nnickel export taskserv.ncl --format json | jq '.staging_stack | length'\n```\n\n---\n\n## Example 4: Composition & Extension Pattern\n\n### Base Infrastructure\n\n```\ncat > production/infrastructure.ncl << 'EOF'\nlet servers = import "./server.ncl" in\nlet taskservs = import "./taskserv.ncl" in\n\n{\n  # Infrastructure with servers + taskservs\n  development = {\n    servers = {\n      app = servers.make_server { name = "dev-app", cpu_cores = 2 },\n      db = servers.make_server { name = "dev-db", cpu_cores = 4 },\n    },\n    taskservs = taskservs.staging_stack,\n  },\n\n  production = {\n    servers = [\n      servers.make_server { name = "prod-app-01", cpu_cores = 8 },\n      servers.make_server { name = "prod-app-02", cpu_cores = 8 },\n      servers.make_server { name = "prod-db-01", cpu_cores = 16 },\n    ],\n    taskservs = taskservs.wuji_k8s_stack & {\n      prometheus = {\n        name = "prometheus",\n        version = "2.45.0",\n        enabled = true,\n        dependencies = [],\n      },\n    },\n  },\n}\nEOF\n\n# Validate composition\nnickel export infrastructure.ncl --format json | jq '.production.servers | length'\n# Output: 3\n\nnickel export infrastructure.ncl --format json | jq '.production.taskservs | keys | length'\n# Output: 5\n```\n\n### Extending Infrastructure (Nickel Advantage!)\n\n```\ncat > production/infrastructure_extended.ncl << 'EOF'\nlet infra = import "./infrastructure.ncl" in\n\n# Add custom fields without modifying base!\n{\n  development = infra.development & {\n    monitoring_enabled = false,\n    cost_optimization = true,\n    auto_shutdown = true,\n  },\n\n  production = infra.production & {\n    monitoring_enabled = true,\n    alert_email = "ops@company.com",\n    backup_enabled = true,\n    backup_frequency = "6h",\n    disaster_recovery_enabled = true,\n    dr_region = "eu-fra1",\n    compliance_level = "SOC2",\n    security_scanning = true,\n  },\n}\nEOF\n\n# Verify extension works (custom fields are preserved!)\nnickel export infrastructure_extended.ncl --format json | \\n  jq '.production | keys'\n# Output includes: monitoring_enabled, alert_email, backup_enabled, etc\n```\n\n---\n\n## Example 5: Validation & Error Handling\n\n### Validation Functions\n\n```\ncat > production/validation.ncl << 'EOF'\nlet validate_server = fun server =>\n  if server.cpu_cores <= 0 then\n    std.record.fail "CPU cores must be positive"\n  else if server.memory_gb <= 0 then\n    std.record.fail "Memory must be positive"\n  else\n    server\nin\n\nlet validate_taskserv = fun ts =>\n  if std.string.length ts.name == 0 then\n    std.record.fail "TaskServ name required"\n  else if std.string.length ts.version == 0 then\n    std.record.fail "TaskServ version required"\n  else\n    ts\nin\n\n{\n  validate_server = validate_server,\n  validate_taskserv = validate_taskserv,\n}\nEOF\n```\n\n### Using Validations\n\n```\ncat > production/validated_config.ncl << 'EOF'\nlet server = import "./server.ncl" in\nlet taskserv = import "./taskserv.ncl" in\nlet validation = import "./validation.ncl" in\n\n{\n  # Valid server (passes validation)\n  valid_server = validation.validate_server {\n    name = "web-01",\n    cpu_cores = 4,\n    memory_gb = 8,\n    zone = "us-nyc1",\n  },\n\n  # Valid taskserv\n  valid_taskserv = validation.validate_taskserv {\n    name = "kubernetes",\n    version = "1.28.0",\n    dependencies = [],\n    enabled = true,\n  },\n}\nEOF\n\n# Test validation\nnickel export validated_config.ncl --format json\n# Should succeed without errors\n\n# Test invalid (uncomment to see error)\n# {\n#   invalid_server = validation.validate_server {\n#     name = "bad-server",\n#     cpu_cores = -1,  # Invalid!\n#     memory_gb = 8,\n#     zone = "us-nyc1",\n#   },\n# }\n```\n\n---\n\n## Test Suite: Bash Script\n\n### Run All Examples\n\n```\n#!/bin/bash\n# test_all_examples.sh\n\nset -e\n\necho "=== Testing Nickel Examples ==="\n\ncd ~/nickel-examples\n\necho "1. Simple Server Configuration..."\ncd simple\nnickel export server.ncl --format json > /dev/null\necho "   ✓ Simple server config valid"\n\necho "2. Complex Provider (UpCloud)..."\ncd ../complex/upcloud\nnickel export upcloud_main.ncl --format json > /dev/null\necho "   ✓ UpCloud provider config valid"\n\necho "3. Production Taskserv..."\ncd ../../production\nnickel export taskserv.ncl --format json > /dev/null\necho "   ✓ Taskserv config valid"\n\necho "4. Infrastructure Composition..."\nnickel export infrastructure.ncl --format json > /dev/null\necho "   ✓ Infrastructure composition valid"\n\necho "5. Extended Infrastructure..."\nnickel export infrastructure_extended.ncl --format json > /dev/null\necho "   ✓ Extended infrastructure valid"\n\necho "6. Validated Config..."\nnickel export validated_config.ncl --format json > /dev/null\necho "   ✓ Validated config valid"\n\necho ""\necho "=== All Tests Passed ✓ ==="\n```\n\n---\n\n## Quick Commands Reference\n\n### Common Nickel Operations\n\n```\n# Validate Nickel syntax\nnickel export config.ncl\n\n# Export as JSON (for inspecting)\nnickel export config.ncl --format json\n\n# Export as TOML (for config files)\nnickel export config.ncl --format toml\n\n# Export as YAML\nnickel export config.ncl --format yaml\n\n# Pretty print JSON output\nnickel export config.ncl --format json | jq .\n\n# Extract specific field\nnickel export config.ncl --format json | jq '.production_server'\n\n# Count array elements\nnickel export config.ncl --format json | jq '.servers | length'\n\n# Check if file has valid syntax only\nnickel typecheck config.ncl\n```\n\n---\n\n## Troubleshooting Examples\n\n### Problem: "unexpected token" with multiple let\n\n```\n# ❌ WRONG\nlet A = {x = 1}\nlet B = {y = 2}\n{A = A, B = B}\n\n# ✅ CORRECT\nlet A = {x = 1} in\nlet B = {y = 2} in\n{A = A, B = B}\n```\n\n### Problem: Function serialization fails\n\n```\n# ❌ WRONG - function will fail to serialize\n{\n  get_value = fun x => x + 1,\n  result = get_value 5,\n}\n\n# ✅ CORRECT - mark function not_exported\n{\n  get_value | not_exported = fun x => x + 1,\n  result = get_value 5,\n}\n```\n\n### Problem: Null values cause export issues\n\n```\n# ❌ WRONG\n{ optional_field = null }\n\n# ✅ CORRECT - use empty string/array/object\n{ optional_field = "" }      # for strings\n{ optional_field = [] }      # for arrays\n{ optional_field = {} }      # for objects\n```\n\n---\n\n## Summary\n\nThese examples are:\n\n- ✅ **Copy-paste ready** - Can run directly\n- ✅ **Executable** - Validated with `nickel export`\n- ✅ **Progressive** - Simple → Complex → Production\n- ✅ **Real patterns** - Based on actual codebase (wuji, upcloud)\n- ✅ **Self-contained** - Each example works independently\n- ✅ **Comparable** - Shows KCL vs Nickel equivalence\n\n**Next**: Use these as templates for your own Nickel configurations.\n\n---\n\n**Version**: 1.0.0\n**Status**: Tested & Verified\n**Last Updated**: 2025-12-15
