The aws:lb/loadBalancer:LoadBalancer resource, part of the Pulumi AWS provider, provisions the load balancer itself: its type (Application, Network, or Gateway), network placement, and operational settings. This guide focuses on three capabilities: creating Application and Network Load Balancers, subnet placement strategies, and static IP assignment.
Load balancers require VPC subnets, security groups (for Application Load Balancers), and optionally S3 buckets for logging or Elastic IPs for static addressing. The examples are intentionally small. Combine them with your own target groups, listeners, and routing rules.
Create an internet-facing Application Load Balancer
Most web applications distribute HTTP/HTTPS traffic across multiple targets using an Application Load Balancer.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const test = new aws.lb.LoadBalancer("test", {
name: "test-lb-tf",
internal: false,
loadBalancerType: "application",
securityGroups: [lbSg.id],
subnets: .map(subnet => (subnet.id)),
enableDeletionProtection: true,
accessLogs: {
bucket: lbLogs.id,
prefix: "test-lb",
enabled: true,
},
tags: {
Environment: "production",
},
});
import pulumi
import pulumi_aws as aws
test = aws.lb.LoadBalancer("test",
name="test-lb-tf",
internal=False,
load_balancer_type="application",
security_groups=[lb_sg["id"]],
subnets=[subnet["id"] for subnet in public],
enable_deletion_protection=True,
access_logs={
"bucket": lb_logs["id"],
"prefix": "test-lb",
"enabled": True,
},
tags={
"Environment": "production",
})
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
var test = new Aws.LB.LoadBalancer("test", new()
{
Name = "test-lb-tf",
Internal = false,
LoadBalancerType = "application",
SecurityGroups = new[]
{
lbSg.Id,
},
Subnets = .Select(subnet =>
{
return subnet.Id;
}).ToList(),
EnableDeletionProtection = true,
AccessLogs = new Aws.LB.Inputs.LoadBalancerAccessLogsArgs
{
Bucket = lbLogs.Id,
Prefix = "test-lb",
Enabled = true,
},
Tags =
{
{ "Environment", "production" },
},
});
});
The loadBalancerType property determines the load balancer’s behavior: application for HTTP/HTTPS routing, network for TCP/UDP connection-level balancing. Setting internal to false creates an internet-facing load balancer with public IP addresses. The subnets property places the load balancer across availability zones, while securityGroups controls inbound traffic. The accessLogs block enables request logging to S3, and enableDeletionProtection prevents accidental deletion.
Create a Network Load Balancer for TCP traffic
Applications requiring ultra-low latency or handling millions of requests per second use Network Load Balancers, which operate at the connection level.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const test = new aws.lb.LoadBalancer("test", {
name: "test-lb-tf",
internal: false,
loadBalancerType: "network",
subnets: .map(subnet => (subnet.id)),
enableDeletionProtection: true,
tags: {
Environment: "production",
},
});
import pulumi
import pulumi_aws as aws
test = aws.lb.LoadBalancer("test",
name="test-lb-tf",
internal=False,
load_balancer_type="network",
subnets=[subnet["id"] for subnet in public],
enable_deletion_protection=True,
tags={
"Environment": "production",
})
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
var test = new Aws.LB.LoadBalancer("test", new()
{
Name = "test-lb-tf",
Internal = false,
LoadBalancerType = "network",
Subnets = .Select(subnet =>
{
return subnet.Id;
}).ToList(),
EnableDeletionProtection = true,
Tags =
{
{ "Environment", "production" },
},
});
});
Network Load Balancers don’t require security groups by default; they operate at Layer 4 and preserve source IP addresses. The subnets property determines availability zone placement. Unlike Application Load Balancers, Network Load Balancers can only add subnets after creation, not remove them.
Assign static Elastic IPs to load balancer nodes
Some integrations require stable IP addresses that don’t change when the load balancer scales or fails over.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const example = new aws.lb.LoadBalancer("example", {
name: "example",
loadBalancerType: "network",
subnetMappings: [
{
subnetId: example1AwsSubnet.id,
allocationId: example1.id,
},
{
subnetId: example2AwsSubnet.id,
allocationId: example2.id,
},
],
});
import pulumi
import pulumi_aws as aws
example = aws.lb.LoadBalancer("example",
name="example",
load_balancer_type="network",
subnet_mappings=[
{
"subnet_id": example1_aws_subnet["id"],
"allocation_id": example1["id"],
},
{
"subnet_id": example2_aws_subnet["id"],
"allocation_id": example2["id"],
},
])
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/lb"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := lb.NewLoadBalancer(ctx, "example", &lb.LoadBalancerArgs{
Name: pulumi.String("example"),
LoadBalancerType: pulumi.String("network"),
SubnetMappings: lb.LoadBalancerSubnetMappingArray{
&lb.LoadBalancerSubnetMappingArgs{
SubnetId: pulumi.Any(example1AwsSubnet.Id),
AllocationId: pulumi.Any(example1.Id),
},
&lb.LoadBalancerSubnetMappingArgs{
SubnetId: pulumi.Any(example2AwsSubnet.Id),
AllocationId: pulumi.Any(example2.Id),
},
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
var example = new Aws.LB.LoadBalancer("example", new()
{
Name = "example",
LoadBalancerType = "network",
SubnetMappings = new[]
{
new Aws.LB.Inputs.LoadBalancerSubnetMappingArgs
{
SubnetId = example1AwsSubnet.Id,
AllocationId = example1.Id,
},
new Aws.LB.Inputs.LoadBalancerSubnetMappingArgs
{
SubnetId = example2AwsSubnet.Id,
AllocationId = example2.Id,
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.lb.LoadBalancer;
import com.pulumi.aws.lb.LoadBalancerArgs;
import com.pulumi.aws.lb.inputs.LoadBalancerSubnetMappingArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var example = new LoadBalancer("example", LoadBalancerArgs.builder()
.name("example")
.loadBalancerType("network")
.subnetMappings(
LoadBalancerSubnetMappingArgs.builder()
.subnetId(example1AwsSubnet.id())
.allocationId(example1.id())
.build(),
LoadBalancerSubnetMappingArgs.builder()
.subnetId(example2AwsSubnet.id())
.allocationId(example2.id())
.build())
.build());
}
}
resources:
example:
type: aws:lb:LoadBalancer
properties:
name: example
loadBalancerType: network
subnetMappings:
- subnetId: ${example1AwsSubnet.id}
allocationId: ${example1.id}
- subnetId: ${example2AwsSubnet.id}
allocationId: ${example2.id}
The subnetMappings property replaces the subnets property when you need control over IP addressing. Each mapping pairs a subnet with an Elastic IP allocation, giving your load balancer predictable addresses for firewall rules or DNS records. This configuration only works with Network Load Balancers.
Assign specific private IPs for internal load balancers
Internal applications sometimes need predictable private IP addresses for integration with on-premises systems.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const example = new aws.lb.LoadBalancer("example", {
name: "example",
loadBalancerType: "network",
subnetMappings: [
{
subnetId: example1.id,
privateIpv4Address: "10.0.1.15",
},
{
subnetId: example2.id,
privateIpv4Address: "10.0.2.15",
},
],
});
import pulumi
import pulumi_aws as aws
example = aws.lb.LoadBalancer("example",
name="example",
load_balancer_type="network",
subnet_mappings=[
{
"subnet_id": example1["id"],
"private_ipv4_address": "10.0.1.15",
},
{
"subnet_id": example2["id"],
"private_ipv4_address": "10.0.2.15",
},
])
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/lb"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := lb.NewLoadBalancer(ctx, "example", &lb.LoadBalancerArgs{
Name: pulumi.String("example"),
LoadBalancerType: pulumi.String("network"),
SubnetMappings: lb.LoadBalancerSubnetMappingArray{
&lb.LoadBalancerSubnetMappingArgs{
SubnetId: pulumi.Any(example1.Id),
PrivateIpv4Address: pulumi.String("10.0.1.15"),
},
&lb.LoadBalancerSubnetMappingArgs{
SubnetId: pulumi.Any(example2.Id),
PrivateIpv4Address: pulumi.String("10.0.2.15"),
},
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
var example = new Aws.LB.LoadBalancer("example", new()
{
Name = "example",
LoadBalancerType = "network",
SubnetMappings = new[]
{
new Aws.LB.Inputs.LoadBalancerSubnetMappingArgs
{
SubnetId = example1.Id,
PrivateIpv4Address = "10.0.1.15",
},
new Aws.LB.Inputs.LoadBalancerSubnetMappingArgs
{
SubnetId = example2.Id,
PrivateIpv4Address = "10.0.2.15",
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.lb.LoadBalancer;
import com.pulumi.aws.lb.LoadBalancerArgs;
import com.pulumi.aws.lb.inputs.LoadBalancerSubnetMappingArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var example = new LoadBalancer("example", LoadBalancerArgs.builder()
.name("example")
.loadBalancerType("network")
.subnetMappings(
LoadBalancerSubnetMappingArgs.builder()
.subnetId(example1.id())
.privateIpv4Address("10.0.1.15")
.build(),
LoadBalancerSubnetMappingArgs.builder()
.subnetId(example2.id())
.privateIpv4Address("10.0.2.15")
.build())
.build());
}
}
resources:
example:
type: aws:lb:LoadBalancer
properties:
name: example
loadBalancerType: network
subnetMappings:
- subnetId: ${example1.id}
privateIpv4Address: 10.0.1.15
- subnetId: ${example2.id}
privateIpv4Address: 10.0.2.15
For internal load balancers, subnetMappings can specify privateIpv4Address instead of allocationId. The load balancer claims these addresses from the subnet’s CIDR range. The addresses must be available and not already assigned to other resources.
Beyond these examples
These snippets focus on specific load balancer features: Application and Network Load Balancer types, subnet placement and IP addressing, and access logging and deletion protection. They’re intentionally minimal rather than full traffic routing solutions.
The examples reference pre-existing infrastructure such as VPC subnets across multiple availability zones, security groups (for Application Load Balancers), S3 buckets for access logs, and Elastic IP allocations (for static IP scenarios). They focus on provisioning the load balancer rather than configuring target groups or listeners.
To keep things focused, common load balancer patterns are omitted, including:
- Cross-zone load balancing configuration (enableCrossZoneLoadBalancing)
- Connection and health check logging (connectionLogs, healthCheckLogs)
- HTTP/2 and TLS header settings (enableHttp2, enableTlsVersionAndCipherSuiteHeaders)
- Idle timeout and client keep-alive tuning (idleTimeout, clientKeepAlive)
- X-Forwarded-For header processing (xffHeaderProcessingMode, enableXffClientPort)
- Target group and listener configuration (separate resources)
These omissions are intentional: the goal is to illustrate how each load balancer feature is wired, not provide drop-in routing modules. See the Load Balancer resource reference for all available configuration options.
Let's create AWS Load Balancers
Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.
Try Pulumi Cloud for FREEFrequently Asked Questions
Load Balancer Types & Configuration
loadBalancerType can be application (default), network, or gateway. Application load balancers support HTTP/2, header manipulation, and connection logs. Network load balancers support Elastic IPs, secondary IPs, and DNS routing policies. Gateway load balancers are for third-party virtual appliances. This property is immutable after creation.subnets or subnetMappings is required. Use subnets for simple subnet attachment. Use subnetMappings when you need to specify Elastic IPs (allocationId) or private IPv4 addresses (privateIpv4Address) for each subnet.network and gateway types, enableCrossZoneLoadBalancing defaults to false. For application load balancers, it’s always true and cannot be disabled.Network Load Balancer Limitations
secondaryIpsAutoAssignedPerSubnet forces recreation.Networking & IP Configuration
ipv4 as the ipAddressType. You can only change to dualstack if the selected subnets are IPv6 enabled.subnetMappings with allocationId to assign Elastic IPs to each subnet, rather than using the subnets property.subnetMappings with privateIpv4Address to specify the private IP for each subnet.Application Load Balancer Features
idleTimeout defaults to 60 seconds for application load balancers. This property is only valid for application type load balancers.xffHeaderProcessingMode determines how the X-Forwarded-For header is modified. Options are append (default), preserve, or remove. This is only valid for application load balancers.desyncMitigationMode controls how the load balancer handles HTTP desync security risks. Valid values are monitor, defensive (default), and strictest.Naming & Resource Management
name must be unique within your AWS account, have a maximum of 32 characters, contain only alphanumeric characters or hyphens, and must not begin or end with a hyphen. If not specified, Pulumi autogenerates a name beginning with tf-lb.enableDeletionProtection to true. This prevents deletion via the AWS API and will prevent Pulumi from deleting the load balancer. It defaults to false.Using a different cloud?
Explore networking guides for other cloud providers: