The aws:lb/targetGroup:TargetGroup resource, part of the Pulumi AWS provider, defines a target group that routes load balancer traffic to registered targets: EC2 instances, IP addresses, Lambda functions, or other ALBs. This guide focuses on three capabilities: target type selection, protocol configuration, and connection termination behavior.
Target groups belong to a VPC (except Lambda targets) and attach to load balancers that distribute traffic. The examples are intentionally small. Combine them with your own load balancers, health checks, and target registration.
Route traffic to EC2 instances by ID
Most deployments route HTTP traffic to EC2 instances within a VPC, using instance IDs as targets.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const main = new aws.ec2.Vpc("main", {cidrBlock: "10.0.0.0/16"});
const test = new aws.lb.TargetGroup("test", {
name: "tf-example-lb-tg",
port: 80,
protocol: "HTTP",
vpcId: main.id,
});
import pulumi
import pulumi_aws as aws
main = aws.ec2.Vpc("main", cidr_block="10.0.0.0/16")
test = aws.lb.TargetGroup("test",
name="tf-example-lb-tg",
port=80,
protocol="HTTP",
vpc_id=main.id)
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/ec2"
"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 {
main, err := ec2.NewVpc(ctx, "main", &ec2.VpcArgs{
CidrBlock: pulumi.String("10.0.0.0/16"),
})
if err != nil {
return err
}
_, err = lb.NewTargetGroup(ctx, "test", &lb.TargetGroupArgs{
Name: pulumi.String("tf-example-lb-tg"),
Port: pulumi.Int(80),
Protocol: pulumi.String("HTTP"),
VpcId: main.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 main = new Aws.Ec2.Vpc("main", new()
{
CidrBlock = "10.0.0.0/16",
});
var test = new Aws.LB.TargetGroup("test", new()
{
Name = "tf-example-lb-tg",
Port = 80,
Protocol = "HTTP",
VpcId = main.Id,
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.ec2.Vpc;
import com.pulumi.aws.ec2.VpcArgs;
import com.pulumi.aws.lb.TargetGroup;
import com.pulumi.aws.lb.TargetGroupArgs;
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 main = new Vpc("main", VpcArgs.builder()
.cidrBlock("10.0.0.0/16")
.build());
var test = new TargetGroup("test", TargetGroupArgs.builder()
.name("tf-example-lb-tg")
.port(80)
.protocol("HTTP")
.vpcId(main.id())
.build());
}
}
resources:
test:
type: aws:lb:TargetGroup
properties:
name: tf-example-lb-tg
port: 80
protocol: HTTP
vpcId: ${main.id}
main:
type: aws:ec2:Vpc
properties:
cidrBlock: 10.0.0.0/16
The targetType defaults to instance, routing traffic to EC2 instances by ID. The port and protocol define how the load balancer communicates with targets. The vpcId scopes the target group to a specific VPC where instances must reside.
Route traffic to specific IP addresses
Container workloads and services outside EC2 often need direct IP-based routing.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const main = new aws.ec2.Vpc("main", {cidrBlock: "10.0.0.0/16"});
const ip_example = new aws.lb.TargetGroup("ip-example", {
name: "tf-example-lb-tg",
port: 80,
protocol: "HTTP",
targetType: "ip",
vpcId: main.id,
});
import pulumi
import pulumi_aws as aws
main = aws.ec2.Vpc("main", cidr_block="10.0.0.0/16")
ip_example = aws.lb.TargetGroup("ip-example",
name="tf-example-lb-tg",
port=80,
protocol="HTTP",
target_type="ip",
vpc_id=main.id)
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/ec2"
"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 {
main, err := ec2.NewVpc(ctx, "main", &ec2.VpcArgs{
CidrBlock: pulumi.String("10.0.0.0/16"),
})
if err != nil {
return err
}
_, err = lb.NewTargetGroup(ctx, "ip-example", &lb.TargetGroupArgs{
Name: pulumi.String("tf-example-lb-tg"),
Port: pulumi.Int(80),
Protocol: pulumi.String("HTTP"),
TargetType: pulumi.String("ip"),
VpcId: main.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 main = new Aws.Ec2.Vpc("main", new()
{
CidrBlock = "10.0.0.0/16",
});
var ip_example = new Aws.LB.TargetGroup("ip-example", new()
{
Name = "tf-example-lb-tg",
Port = 80,
Protocol = "HTTP",
TargetType = "ip",
VpcId = main.Id,
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.ec2.Vpc;
import com.pulumi.aws.ec2.VpcArgs;
import com.pulumi.aws.lb.TargetGroup;
import com.pulumi.aws.lb.TargetGroupArgs;
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 main = new Vpc("main", VpcArgs.builder()
.cidrBlock("10.0.0.0/16")
.build());
var ip_example = new TargetGroup("ip-example", TargetGroupArgs.builder()
.name("tf-example-lb-tg")
.port(80)
.protocol("HTTP")
.targetType("ip")
.vpcId(main.id())
.build());
}
}
resources:
ip-example:
type: aws:lb:TargetGroup
properties:
name: tf-example-lb-tg
port: 80
protocol: HTTP
targetType: ip
vpcId: ${main.id}
main:
type: aws:ec2:Vpc
properties:
cidrBlock: 10.0.0.0/16
Setting targetType to ip allows you to register specific IP addresses as targets. This supports container tasks with dynamic IPs, on-premises resources via PrivateLink, or any endpoint within VPC subnets or RFC 1918/6598 ranges. You cannot use publicly routable IPs.
Invoke Lambda functions from load balancer requests
Application Load Balancers can route HTTP requests directly to Lambda functions for serverless APIs.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const lambda_example = new aws.lb.TargetGroup("lambda-example", {
name: "tf-example-lb-tg",
targetType: "lambda",
});
import pulumi
import pulumi_aws as aws
lambda_example = aws.lb.TargetGroup("lambda-example",
name="tf-example-lb-tg",
target_type="lambda")
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.NewTargetGroup(ctx, "lambda-example", &lb.TargetGroupArgs{
Name: pulumi.String("tf-example-lb-tg"),
TargetType: pulumi.String("lambda"),
})
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 lambda_example = new Aws.LB.TargetGroup("lambda-example", new()
{
Name = "tf-example-lb-tg",
TargetType = "lambda",
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.lb.TargetGroup;
import com.pulumi.aws.lb.TargetGroupArgs;
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 lambda_example = new TargetGroup("lambda-example", TargetGroupArgs.builder()
.name("tf-example-lb-tg")
.targetType("lambda")
.build());
}
}
resources:
lambda-example:
type: aws:lb:TargetGroup
properties:
name: tf-example-lb-tg
targetType: lambda
When targetType is lambda, the target group routes requests to a Lambda function without requiring port or protocol configuration. The load balancer invokes the function with HTTP request details and expects an HTTP response format.
Preserve connections to unhealthy targets
Some TCP workloads maintain long-lived connections even when targets fail health checks.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const tcp_example = new aws.lb.TargetGroup("tcp-example", {
name: "tf-example-lb-nlb-tg",
port: 25,
protocol: "TCP",
vpcId: main.id,
targetHealthStates: [{
enableUnhealthyConnectionTermination: false,
}],
});
import pulumi
import pulumi_aws as aws
tcp_example = aws.lb.TargetGroup("tcp-example",
name="tf-example-lb-nlb-tg",
port=25,
protocol="TCP",
vpc_id=main["id"],
target_health_states=[{
"enable_unhealthy_connection_termination": False,
}])
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.NewTargetGroup(ctx, "tcp-example", &lb.TargetGroupArgs{
Name: pulumi.String("tf-example-lb-nlb-tg"),
Port: pulumi.Int(25),
Protocol: pulumi.String("TCP"),
VpcId: pulumi.Any(main.Id),
TargetHealthStates: lb.TargetGroupTargetHealthStateArray{
&lb.TargetGroupTargetHealthStateArgs{
EnableUnhealthyConnectionTermination: pulumi.Bool(false),
},
},
})
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 tcp_example = new Aws.LB.TargetGroup("tcp-example", new()
{
Name = "tf-example-lb-nlb-tg",
Port = 25,
Protocol = "TCP",
VpcId = main.Id,
TargetHealthStates = new[]
{
new Aws.LB.Inputs.TargetGroupTargetHealthStateArgs
{
EnableUnhealthyConnectionTermination = false,
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.lb.TargetGroup;
import com.pulumi.aws.lb.TargetGroupArgs;
import com.pulumi.aws.lb.inputs.TargetGroupTargetHealthStateArgs;
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 tcp_example = new TargetGroup("tcp-example", TargetGroupArgs.builder()
.name("tf-example-lb-nlb-tg")
.port(25)
.protocol("TCP")
.vpcId(main.id())
.targetHealthStates(TargetGroupTargetHealthStateArgs.builder()
.enableUnhealthyConnectionTermination(false)
.build())
.build());
}
}
resources:
tcp-example:
type: aws:lb:TargetGroup
properties:
name: tf-example-lb-nlb-tg
port: 25
protocol: TCP
vpcId: ${main.id}
targetHealthStates:
- enableUnhealthyConnectionTermination: false
The targetHealthStates block controls connection termination behavior for Network Load Balancers using TCP or TLS. Setting enableUnhealthyConnectionTermination to false keeps connections open when targets become unhealthy, allowing graceful session cleanup rather than immediate termination.
Beyond these examples
These snippets focus on specific target group features: target type selection, protocol and port configuration, and connection termination behavior. They’re intentionally minimal rather than full load balancing deployments.
The examples may reference pre-existing infrastructure such as VPCs for instance and IP target groups, and load balancers to attach target groups to. They focus on configuring the target group rather than provisioning the surrounding infrastructure.
To keep things focused, common target group patterns are omitted, including:
- Health check configuration (interval, timeout, thresholds)
- Session stickiness and cookie settings
- Deregistration delay and connection draining
- Cross-zone load balancing and algorithm selection
These omissions are intentional: the goal is to illustrate how each target group feature is wired, not provide drop-in load balancing modules. See the Target Group resource reference for all available configuration options.
Let's configure AWS Load Balancer Target Groups
Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.
Try Pulumi Cloud for FREEFrequently Asked Questions
Target Types & Configuration
Requirements vary by targetType:
- instance, ip, alb: Require
port,protocol, andvpcId - lambda: Does not use
port,protocol, orvpcId
targetType to either instance or ip.instance, ip, and alb target types but not lambda. Application Load Balancers support instance, ip, and lambda but not alb.Immutability & Naming
targetType, port, protocol, vpcId, name, namePrefix, ipAddressType, protocolVersion, and targetControlPort.namePrefix (max 6 characters) to auto-generate unique names.Load Balancing Algorithms
round_robin (default), least_outstanding_requests, and weighted_random. This setting only applies to ALB target groups.weighted_random load balancing algorithm. Set loadBalancingAnomalyMitigation to "on" to enable it (default is "off").Deregistration & Health
deregistrationDelay (0-3600 seconds, default 300) controls how long ELB waits before marking a deregistering target as unused. slowStart (30-900 seconds or 0, default 0) is a warm-up period before new targets receive full traffic.targetHealthStates with enableUnhealthyConnectionTermination: false. This is only applicable for Network Load Balancer target groups when protocol is TCP or TLS.Protocol & IP Configuration
ipAddressType to ipv6 when targetType is ip. The ipAddressType property only works with IP-based target groups and is immutable.Using a different cloud?
Explore networking guides for other cloud providers: