Nelknet.Cdktf
F# computation expressions and helpers that sit on top of the CDK for Terraform (CDKTF) .NET bindings. The library is generated directly from a provider's JSII schema so the surface stays in sync with the official SDKs while feeling idiomatic in F# (maps as sequences, arrays as sequences, boolean flags as bool, etc.).
Highlights
Screen.Recording.2025-10-20.at.4.16.40.PM.mov
- Schema‑driven generation – provider projects carry MSBuild metadata; run
dotnet build(ordotnet build -p:ForceCodeGen=true) to refreshsrc/Providers/<Provider>/Generated/...and commit the regenerated surface alongside your changes. - F#‑friendly operations – Terraform maps become
seq<string * string>, repeated fields acceptseq<'T>, and common unions (e.g.,bool | cdktf.IResolvable) expose overloads so you don't have to passobj. - Compile-time required checks – generated builders track required custom operations with phantom types (
Missing/Present), so omitting a mandatory field (e.g.,name,server_type) produces a compile-timeCompilerMessageerror instead of a runtime failure. - Ambient stack support –
stack "name" { ... }keeps the currentTerraformStackavailable without threading it through every builder.
Getting Started
Install the NuGet packages for the providers you need, then create your infrastructure as code in F#.
Prerequisites
- .NET 8 SDK (
dotnet --version≥ 8.0) - Node.js 20.x or 22.x with npm (required by the CDKTF CLI)
- CDKTF CLI
- Terraform/OpenTofu CLI
- Cloud credentials for the providers you plan to use (e.g.,
HCLOUD_TOKENfor Hetzner, etc.)
Quick Start
-
Create an infrastructure project
mkdir Demo.Infra cd Demo.Infra dotnet new console -lang F# -
Install the providers you need
dotnet add package Nelknet.Cdktf.Providers.Aws # For AWS dotnet add package Nelknet.Cdktf.Providers.Azurerm # For Azure dotnet add package Nelknet.Cdktf.Providers.Hcloud # For Hetzner
Provider packages bring
Nelknet.Cdktf.Core, the CDKTF runtime, and the generated C# bindings. -
Write your infrastructure
open Nelknet.Cdktf open Nelknet.Cdktf.Providers open Nelknet.Cdktf.Terraform [<EntryPoint>] let main _ = let app = stack "demo" { let _ = Aws.provider "aws" { region "us-east-1" } Aws.s3Bucket "state" { bucket "demo-state-bucket" } } app.Synth() 0
-
Add a
cdktf.jsonmanifest at the repo root{ "language": "csharp", "app": "dotnet run", "codeMakerOutput": "generated", "terraformProviders": [ "hashicorp/aws@=5.100.0" ], "terraformModules": [], "context": {} } -
Deploy your infrastructure
cdktf synth # Run the app command and emit Terraform JSON cdktf deploy # Apply the stack (requires provider credentials)
Example: Hetzner Cloud Server
Here's a complete example using the Hetzner Cloud provider:
open Nelknet.Cdktf open Nelknet.Cdktf.Providers open Nelknet.Cdktf.Terraform let apiToken = System.Environment.GetEnvironmentVariable "HCLOUD_TOKEN" let app = stack "hcloud-example" { // Register the provider let _ = Hcloud.provider "hcloud" { token apiToken poll_interval "750ms" } // Create a server - schema-driven CE with compile-time checks let server = Hcloud.server "sample-server" { name "fsharp-sample" // Required field server_type "cpx11" // Required field image "ubuntu-22.04" // Required field labels [ "module", "nelknet" ] // Maps as sequences } // Expose outputs Terraform.output "server-name" { value server.Name description "Expose the created Hetzner server name" } |> ignore } app.Synth()
Deploy with:
export HCLOUD_TOKEN=... # Your Hetzner API token cdktf deploy --auto-approve cdktf destroy --auto-approve # Clean up when done
Development
Building from Source
After cloning this repository:
dotnet build -p:ForceCodeGen=true
This automatically:
- Runs the Bootstrap tool (via
Directory.Build.targets) which installs Node dependencies if needed and downloads provider bindings - Generates F# DSL code for all providers
- Builds the entire solution
The build process is fully automated - you don't need to run npm install or any other setup commands manually.
Adding a New Provider
Adding a new provider is streamlined with the Bootstrap project:
-
Ask CDKTF to add the provider
cdktf provider add hashicorp/random@=3.6.0 --language csharp --force-local
-
Scaffold any missing provider projects
dotnet fsi tools/scaffold-providers.fsx
-
Add the projects to the solution
dotnet sln add src/Providers/Random/Nelknet.Cdktf.Providers.Random.fsproj dotnet sln add generated/random/random.csproj
-
Run the build
dotnet build -p:ForceCodeGen=true
-
Commit everything
- The updated
cdktf.json - The new provider's
.fsprojfile insrc/Providers/<Provider>/ - Any documentation updates
- All generated changes (both
generated/<provider>andsrc/Providers/<Provider>/Generated/**)
Push your branch and open a PR. The build workflow simply runs
dotnet build, so the PR must include the regenerated artifacts to stay green. - The updated
What Happens During the Build
The Bootstrap project (tools/Nelknet.Cdktf.Bootstrap/) automatically:
- Reads providers from
cdktf.json - Downloads missing providers using
cdktf provider add - Normalizes generated C# projects for Central Package Management
- Creates provider F# projects from the template in
src/Providers/_Template/ - Caches everything to avoid redundant downloads
Upgrading an Existing Provider
To upgrade a provider version:
- Update the version in
cdktf.json. - Run
dotnet build -p:ForceCodeGen=true(orscripts/regenerate.sh) to refresh the generated surface. - Commit the updated
cdktf.jsontogether with the regenerated files and open a PR.
Packaging
Pack the core and providers independently:
# Core DSL dotnet pack src/Core/Nelknet.Cdktf.Core/Nelknet.Cdktf.Core.fsproj -c Release -o artifacts # Hetzner provider (generated) dotnet pack src/Providers/Hcloud/Nelknet.Cdktf.Providers.Hcloud.fsproj -c Release -o artifacts
Publish whichever packages you need (dotnet nuget push artifacts/*.nupkg). Consumers can depend on Nelknet.Cdktf.Core plus only the provider packages they require.
The repository also ships a Release workflow (Actions tab) that builds, packs, and publishes every package to NuGet. Set NUGET_API_KEY in your environment or as a repository secret before running it.
Happy infrastructure hacking in F#!