Header menu logo FsCDK

Getting Started with FsCDK - Extended Features

Welcome to the extended FsCDK! This guide will help you understand the new features and how to use them effectively.

What's New?

FsCDK now includes builders for:

All following AWS Well-Architected Framework best practices!

Quick Start Examples

1. Create a Secure VPC

#r "../src/bin/Release/net8.0/publish/Amazon.JSII.Runtime.dll"
#r "../src/bin/Release/net8.0/publish/Constructs.dll"
#r "../src/bin/Release/net8.0/publish/Amazon.CDK.Lib.dll"
#r "../src/bin/Release/net8.0/publish/System.Text.Json.dll"
#r "../src/bin/Release/net8.0/publish/FsCDK.dll"

open FsCDK

vpc "MyVpc" {
    maxAzs 2 // Multi-AZ for high availability
    natGateways 1 // Cost-optimized
    cidr "10.0.0.0/16" // IP address range
}

What you get:

2. Add a PostgreSQL Database

Here's how to add a PostgreSQL database (shown in full stack example below):

rdsInstance "MyDatabase" {
    vpc myVpc
    postgresEngine // PostgreSQL 15
    instanceType (InstanceType.Of(InstanceClass.BURSTABLE3, InstanceSize.SMALL))
    allocatedStorage 20

    // Automatic best practices:
    // Encrypted storage
    // 7-day automated backups
    // Auto minor version upgrades
    // Private subnet placement

    multiAz true // High availability
    databaseName "myapp"
}

What you get:

3. Set Up User Authentication

open Amazon.CDK.AWS.Cognito

stack "MyApp" {
    // Create user pool
    let! myUserPool =
        userPool "MyUserPool" {
            signInWithEmail // Users sign in with email
            selfSignUpEnabled true // Allow self-registration
            mfa Mfa.OPTIONAL // Users can enable MFA

        // Automatic best practices:
        // Strong password policy (8+ chars, mixed case, digits, symbols)
        // Email verification required
        // Account recovery via email
        }

    // Create an app client
    userPoolClient "MyAppClient" {
        userPool myUserPool
        generateSecret false // For web/mobile apps
    }

// Automatic best practices:
// SRP authentication flow
// Prevents user existence errors
// Reasonable token expiration times
}

What you get:

4. Add a CDN for Fast Delivery

What you get:

Complete Application Stack

FsCDK Stack Architecture

FsCDK App structure showing multiple stacks with constructs organized hierarchically. Each stack contains AWS resources (S3, Lambda, EC2) managed by your infrastructure-as-code heroes!

Here's how to combine everything into a production-ready stack:

open Amazon.CDK.AWS.S3
open Amazon.CDK.AWS.Lambda

Best Practices Baked In

FsCDK automatically applies AWS best practices:

Security

High Availability

Cost Optimization

Performance

Common Patterns

Pattern 1: Web Application with Auth

stack "WebApp" {
    vpc "WebVpc" { () }

    userPool "Users" {
        signInWithEmail
        selfSignUpEnabled true
    }

    lambda "Api" {
        runtime Runtime.DOTNET_8
        handler "Api::Handler"
        code "./publish"
    }

    bucket "Assets" { versioned true }
}

Pattern 2: Data Processing Pipeline

stack "DataPipeline" {
    let! myVpc = vpc "DataVpc" { () }

    rdsInstance "DataWarehouse" {
        vpc myVpc
        postgresEngine
        multiAz true
    }

    lambda "Processor" {
        runtime Runtime.DOTNET_8
        handler "Processor::Handler"
        code "./publish"
        timeout 300.0 // 5 minutes for data processing
        memorySize 1024 // More memory for processing
    }

    bucket "DataLake" {
        versioned true
    // lifecycleRules [ /* ... */ ]
    }
}

Pattern 3: Serverless API with CDN

open Amazon.CDK.AWS.DynamoDB

Migration from Existing FsCDK

Good news! No breaking changes! Your existing code continues to work:

// Your existing code still works!
stack "MyStack" {
    lambda "MyFunction" {
        runtime Runtime.DOTNET_8
        handler "index.handler"
        code "./lambda"
    }

    table "MyTable" { partitionKey "id" AttributeType.STRING }
}

// Just add new features when you need them
stack "EnhancedStack" {
    // Existing services
    lambda "MyFunction" {
        runtime Runtime.DOTNET_8
        handler "index.handler"
        code "./lambda"
    }

    // New services
    let! myVpc = vpc "MyVpc" { () }

    rdsInstance "MyDB" {
        vpc myVpc
        postgresEngine
    }

    userPool "MyAuth" { signInWithEmail }
}

Learning Resources

  1. Examples: See Multi-Tier Example for a complete application
  2. Security: Read IAM Best Practices for security guidance
  3. API Docs: Check XML documentation comments in code
  4. AWS Docs: AWS CDK Documentation

Next Steps

  1. Install FsCDK: dotnet add package FsCDK
  2. Create your first VPC: vpc "MyVpc" { }
  3. Add a database: rdsInstance "MyDB" { vpc myVpc; postgresEngine }
  4. Deploy: cdk deploy
  5. Monitor in AWS Console

Getting Help

Tips for Success

  1. Start Small: Begin with a simple VPC or database
  2. Use Defaults: FsCDK defaults are production-ready
  3. Review Generated Templates: Run cdk synth to see CloudFormation
  4. Test Incrementally: Deploy small changes frequently
  5. Follow Best Practices: Read the IAM best practices guide

Cost Management

Monitor your costs:

Troubleshooting

Build Errors

# Clean and rebuild
dotnet clean
dotnet build

Deployment Issues

# Verify CDK bootstrap
cdk bootstrap aws://ACCOUNT/REGION

# Check diff before deploying
cdk diff

# Deploy with verbose output
cdk deploy --verbose

Resource Already Exists

# Import existing resources
cdk import

# Or use different names
vpc "MyVpc-v2" { ... }

What's Available?

FsCDK supports 30+ AWS services including:

See the full list of supported services in the documentation.


Ready to build secure, scalable infrastructure with F#? Let's go!

namespace FsCDK
val vpc: name: string -> VpcBuilder
<summary>Creates a VPC configuration with AWS best practices.</summary>
<param name="name">The VPC name.</param>
<code lang="fsharp"> vpc "MyVpc" { maxAzs 2 natGateways 1 cidr "10.0.0.0/16" } </code>
custom operation: maxAzs (int) Calls VpcBuilder.MaxAzs
<summary>Sets the maximum number of Availability Zones to use.</summary>
<param name="config">The current VPC configuration.</param>
<param name="maxAzs">The maximum number of AZs (default: 2 for HA).</param>
<code lang="fsharp"> vpc "MyVpc" { maxAzs 3 } </code>
custom operation: natGateways (int) Calls VpcBuilder.NatGateways
<summary>Sets the number of NAT Gateways.</summary>
<param name="config">The current VPC configuration.</param>
<param name="natGateways">The number of NAT gateways (default: 1 for cost optimization).</param>
<code lang="fsharp"> vpc "MyVpc" { natGateways 2 } </code>
custom operation: cidr (string) Calls VpcBuilder.Cidr
<summary>Sets the CIDR block for the VPC.</summary>
<param name="config">The current VPC configuration.</param>
<param name="cidr">The CIDR block (e.g., "10.0.0.0/16").</param>
<code lang="fsharp"> vpc "MyVpc" { cidr "10.0.0.0/16" } </code>
namespace Amazon
namespace Amazon.CDK
namespace Amazon.CDK.AWS
namespace Amazon.CDK.AWS.Cognito
val stack: name: string -> StackBuilder
<summary>Creates an AWS CDK Stack construct.</summary>
<param name="name">The name of the stack.</param>
<code lang="fsharp"> stack "MyStack" { lambda myFunction bucket myBucket } </code>
val myUserPool: IUserPool
val userPool: name: string -> UserPoolBuilder
<summary>Creates a Cognito User Pool with AWS best practices.</summary>
<param name="name">The user pool name.</param>
<code lang="fsharp"> userPool "MyUserPool" { signInWithEmail selfSignUpEnabled true mfa Mfa.OPTIONAL } </code>
custom operation: signInWithEmail Calls UserPoolBuilder.SignInWithEmail
<summary>Enables email only as sign-in alias.</summary>
custom operation: selfSignUpEnabled (bool) Calls UserPoolBuilder.SelfSignUpEnabled
<summary>Enables or disables self sign-up.</summary>
custom operation: mfa (Mfa) Calls UserPoolBuilder.Mfa
<summary>Sets MFA configuration.</summary>
[<Struct>] type Mfa = | OFF = 0 | OPTIONAL = 1 | REQUIRED = 2
field Mfa.OPTIONAL: Mfa = 1
val userPoolClient: name: string -> UserPoolClientBuilder
<summary>Creates a Cognito User Pool Client.</summary>
<param name="name">The client name.</param>
<code lang="fsharp"> userPoolClient "MyAppClient" { userPool myUserPool generateSecret false } </code>
custom operation: userPool (IUserPool) Calls UserPoolClientBuilder.UserPool
<summary>Sets the user pool.</summary>
custom operation: generateSecret (bool) Calls UserPoolClientBuilder.GenerateSecret
<summary>Enables or disables secret generation.</summary>
val myBehavior: Amazon.CDK.AWS.CloudFront.IBehaviorOptions
module CloudFrontBehaviors from FsCDK
<summary> Factory helpers to build common IBehaviorOptions for S3 and HTTP origins. These helpers are useful if you prefer to construct behaviors and pass them via defaultBehavior/additionalBehavior. </summary>
val httpBehaviorDefault: domainName: string -> (bool option -> Amazon.CDK.AWS.CloudFront.IBehaviorOptions)
union case Option.Some: Value: 'T -> Option<'T>
val cloudFrontDistribution: name: string -> DistributionBuilder
<summary>Creates a CloudFront distribution with AWS best practices.</summary>
<param name="name">The distribution name.</param>
<remarks> Example: cloudFrontDistribution "MyCDN" { s3DefaultBehavior myBucket defaultRootObject "index.html" domainName "static.example.com" priceClass PriceClass.PRICE_CLASS_100 } </remarks>
custom operation: defaultBehavior (Amazon.CDK.AWS.CloudFront.IBehaviorOptions) Calls DistributionBuilder.DefaultBehavior
<summary>Sets the default behavior from a pre-built IBehaviorOptions.</summary>
custom operation: defaultRootObject (string) Calls DistributionBuilder.DefaultRootObject
<summary>Sets the default root object (e.g., "index.html").</summary>
namespace Amazon.CDK.AWS.S3
namespace Amazon.CDK.AWS.Lambda
val get: unit -> {| Account: string; Region: string |}
namespace System
type Environment = static member Exit: exitCode: int -> unit static member ExpandEnvironmentVariables: name: string -> string static member FailFast: message: string -> unit + 1 overload static member GetCommandLineArgs: unit -> string array static member GetEnvironmentVariable: variable: string -> string + 1 overload static member GetEnvironmentVariables: unit -> IDictionary + 1 overload static member GetFolderPath: folder: SpecialFolder -> string + 1 overload static member GetLogicalDrives: unit -> string array static member SetEnvironmentVariable: variable: string * value: string -> unit + 1 overload static member CommandLine: string ...
<summary>Provides information about, and means to manipulate, the current environment and platform. This class cannot be inherited.</summary>
System.Environment.GetEnvironmentVariable(variable: string) : string
System.Environment.GetEnvironmentVariable(variable: string, target: System.EnvironmentVariableTarget) : string
val config: {| Account: string; Region: string |}
module Config from Getting-started-extended
val cdnBehavior: Amazon.CDK.AWS.CloudFront.IBehaviorOptions
custom operation: env (Amazon.CDK.IEnvironment) Calls StackBuilder.Env
val environment: EnvironmentBuilder
<summary>Creates an AWS CDK Environment configuration.</summary>
<code lang="fsharp"> environment { account "123456789012" region "us-west-2" } </code>
custom operation: account (string) Calls EnvironmentBuilder.Account
<summary>Sets the AWS account ID for the environment.</summary>
<param name="config">The current configuration.</param>
<param name="accountId">The AWS account ID.</param>
<code lang="fsharp"> environment { account "123456789012" } </code>
anonymous record field Account: string
custom operation: region (string) Calls EnvironmentBuilder.Region
<summary>Sets the AWS region for the environment.</summary>
<param name="config">The current configuration.</param>
<param name="regionName">The AWS region name.</param>
<code lang="fsharp"> environment { region "us-west-2" } </code>
anonymous record field Region: string
custom operation: description (string) Calls StackBuilder.Description
<summary>Sets the stack description.</summary>
<param name="config">The current stack configuration.</param>
<param name="desc">A description of the stack.</param>
<code lang="fsharp"> stack "MyStack" { description "My application stack" } </code>
custom operation: tags ((string * string) list) Calls StackBuilder.Tags
<summary>Adds tags to the stack.</summary>
<param name="config">The current stack configuration.</param>
<param name="tags">A list of key-value pairs for tagging.</param>
<code lang="fsharp"> stack "MyStack" { tags [ "Environment", "Production"; "Team", "DevOps" ] } </code>
val myVpc: Amazon.CDK.AWS.EC2.IVpc
val rdsInstance: name: string -> DatabaseInstanceBuilder
<summary>Creates an RDS Database Instance with AWS best practices.</summary>
<param name="name">The database instance name.</param>
<code lang="fsharp"> rdsInstance "MyDatabase" { vpc myVpc postgresEngine PostgresEngineVersion.VER_15 instanceType (InstanceType.Of(InstanceClass.BURSTABLE3, InstanceSize.SMALL)) multiAz true backupRetentionDays 7.0 } </code>
custom operation: vpc (Amazon.CDK.AWS.EC2.IVpc) Calls DatabaseInstanceBuilder.Vpc
<summary>Sets the VPC.</summary>
custom operation: postgresEngine (Amazon.CDK.AWS.RDS.PostgresEngineVersion option) Calls DatabaseInstanceBuilder.PostgresEngine
<summary>Sets PostgreSQL as the database engine with a specific version.</summary>
custom operation: multiAz (bool) Calls DatabaseInstanceBuilder.MultiAz
<summary>Enables or disables Multi-AZ deployment.</summary>
custom operation: allocatedStorage (int) Calls DatabaseInstanceBuilder.AllocatedStorage
<summary>Sets the allocated storage in GB.</summary>
custom operation: databaseName (string) Calls DatabaseInstanceBuilder.DatabaseName
<summary>Sets the database name.</summary>
val bucket: name: string -> BucketBuilder
custom operation: versioned (bool) Calls BucketBuilder.Versioned
<summary> Enables or disables versioning for the S3 bucket. **Security Best Practice:** Enable versioning for: - Critical data that requires audit trails - Data subject to compliance requirements (HIPAA, SOC2, etc.) - Production buckets storing business data **Cost Consideration:** Versioning stores all versions of objects, increasing storage costs. Only disable for: - Temporary/cache buckets - Build artifacts with short lifecycle - Development/testing buckets **Default:** false (opt-in for cost optimization) </summary>
<param name="value">True to enable versioning, false to disable.</param>
<param name="config">The current bucket configuration.</param>
<code lang="fsharp"> bucket "production-data" { versioned true // Enable for production } bucket "cache-bucket" { versioned false // Disable for temp data } </code>
custom operation: encryption (BucketEncryption) Calls BucketBuilder.Encryption
[<Struct>] type BucketEncryption = | UNENCRYPTED = 0 | KMS_MANAGED = 1 | S3_MANAGED = 2 | KMS = 3 | DSSE_MANAGED = 4 | DSSE = 5
field BucketEncryption.S3_MANAGED: BucketEncryption = 2
custom operation: blockPublicAccess (BlockPublicAccess) Calls BucketBuilder.BlockPublicAccess
Multiple items
type BlockPublicAccess = inherit DeputyBase new: options: IBlockPublicAccessOptions -> unit member BlockPublicAcls: Nullable<bool> member BlockPublicPolicy: Nullable<bool> member IgnorePublicAcls: Nullable<bool> member RestrictPublicBuckets: Nullable<bool> static member BLOCK_ACLS: BlockPublicAccess static member BLOCK_ACLS_ONLY: BlockPublicAccess static member BLOCK_ALL: BlockPublicAccess

--------------------
BlockPublicAccess(options: IBlockPublicAccessOptions) : BlockPublicAccess
property BlockPublicAccess.BLOCK_ALL: BlockPublicAccess with get
val lambda: name: string -> FunctionBuilder
<summary>Creates a Lambda function configuration.</summary>
<param name="name">The function name.</param>
<code lang="fsharp"> lambda "MyFunction" { handler "index.handler" runtime Runtime.NODEJS_18_X code "./lambda" timeout 30.0 } </code>
custom operation: runtime (Runtime) Calls FunctionBuilder.Runtime
<summary>Sets the runtime for the Lambda function.</summary>
<param name="config">The function configuration.</param>
<param name="runtime">The Lambda runtime.</param>
<code lang="fsharp"> lambda "MyFunction" { runtime Runtime.NODEJS_18_X } </code>
Multiple items
type Runtime = inherit DeputyBase new: name: string * ?family: Nullable<RuntimeFamily> * ?props: ILambdaRuntimeProps -> unit member RuntimeEquals: other: Runtime -> bool member ToString: unit -> string member BundlingImage: DockerImage member Family: Nullable<RuntimeFamily> member IsVariable: bool member Name: string member SupportsCodeGuruProfiling: bool member SupportsInlineCode: bool ...

--------------------
Runtime(name: string, ?family: System.Nullable<RuntimeFamily>, ?props: ILambdaRuntimeProps) : Runtime
property Runtime.DOTNET_8: Runtime with get
custom operation: handler (string) Calls FunctionBuilder.Handler
<summary>Sets the handler for the Lambda function.</summary>
<param name="config">The function configuration.</param>
<param name="handler">The handler name (e.g., "index.handler").</param>
<code lang="fsharp"> lambda "MyFunction" { handler "index.handler" } </code>
custom operation: code (Code) Calls FunctionBuilder.Code
<summary>Sets the code source from a Code object.</summary>
<param name="config">The function configuration.</param>
<param name="path">The Code object.</param>
<code lang="fsharp"> lambda "MyFunction" { code (Code.FromBucket myBucket "lambda.zip") } </code>
custom operation: timeout (float) Calls FunctionBuilder.Timeout
<summary>Sets the timeout for the Lambda function.</summary>
<param name="config">The function configuration.</param>
<param name="seconds">The timeout in seconds.</param>
<code lang="fsharp"> lambda "MyFunction" { timeout 30.0 } </code>
custom operation: memorySize (int) Calls FunctionBuilder.MemorySize
<summary>Sets the memory allocation for the Lambda function.</summary>
<param name="config">The function configuration.</param>
<param name="mb">The memory size in megabytes.</param>
<code lang="fsharp"> lambda "MyFunction" { memory 512 } </code>
custom operation: environment ((string * string) list) Calls FunctionBuilder.Environment
<summary>Sets environment variables for the Lambda function.</summary>
<param name="config">The function configuration.</param>
<param name="env">List of key-value pairs for environment variables.</param>
<code lang="fsharp"> lambda "MyFunction" { environment [ "KEY1", "value1"; "KEY2", "value2" ] } </code>
namespace Amazon.CDK.AWS.DynamoDB
val apiOrigin: Amazon.CDK.AWS.CloudFront.IBehaviorOptions
val table: name: string -> TableBuilder
<summary>Creates a DynamoDB table configuration.</summary>
<param name="name">The table name.</param>
<code lang="fsharp"> table "MyTable" { partitionKey "id" AttributeType.STRING billingMode BillingMode.PAY_PER_REQUEST } </code>
custom operation: partitionKey (string) (AttributeType) Calls TableBuilder.PartitionKey
<summary>Sets the partition key for the table.</summary>
<param name="config">The current table configuration.</param>
<param name="name">The attribute name for the partition key.</param>
<param name="attrType">The attribute type (STRING, NUMBER, or BINARY).</param>
<code lang="fsharp"> table "MyTable" { partitionKey "id" AttributeType.STRING } </code>
[<Struct>] type AttributeType = | BINARY = 0 | NUMBER = 1 | STRING = 2
field AttributeType.STRING: AttributeType = 2
custom operation: billingMode (BillingMode) Calls TableBuilder.BillingMode
<summary>Sets the billing mode for the table.</summary>
<param name="config">The current table configuration.</param>
<param name="mode">The billing mode (PAY_PER_REQUEST or PROVISIONED).</param>
<code lang="fsharp"> table "MyTable" { billingMode BillingMode.PAY_PER_REQUEST } </code>
[<Struct>] type BillingMode = | PAY_PER_REQUEST = 0 | PROVISIONED = 1
field BillingMode.PAY_PER_REQUEST: BillingMode = 0

Type something to start searching.