The aws:ec2/instance:Instance resource, part of the Pulumi AWS provider, defines an EC2 virtual machine instance: its AMI, instance type, networking, and compute options. This guide focuses on four capabilities: dynamic AMI selection, spot instance requests, network interface attachment, and CPU topology configuration.
Instances typically run in a VPC with subnets and security groups, and may reference network interfaces or require IAM permissions. The examples are intentionally small. Combine them with your own VPC, security groups, SSH keys, and IAM roles.
Launch an instance with dynamic AMI lookup
Most deployments begin by selecting an AMI that matches your OS and architecture requirements. Dynamic AMI lookup ensures you always use the latest version without hardcoding IDs.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const ubuntu = aws.ec2.getAmi({
mostRecent: true,
filters: [
{
name: "name",
values: ["ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-*"],
},
{
name: "virtualization-type",
values: ["hvm"],
},
],
owners: ["099720109477"],
});
const example = new aws.ec2.Instance("example", {
ami: ubuntu.then(ubuntu => ubuntu.id),
instanceType: aws.ec2.InstanceType.T3_Micro,
tags: {
Name: "HelloWorld",
},
});
import pulumi
import pulumi_aws as aws
ubuntu = aws.ec2.get_ami(most_recent=True,
filters=[
{
"name": "name",
"values": ["ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-*"],
},
{
"name": "virtualization-type",
"values": ["hvm"],
},
],
owners=["099720109477"])
example = aws.ec2.Instance("example",
ami=ubuntu.id,
instance_type=aws.ec2.InstanceType.T3_MICRO,
tags={
"Name": "HelloWorld",
})
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/ec2"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
ubuntu, err := ec2.LookupAmi(ctx, &ec2.LookupAmiArgs{
MostRecent: pulumi.BoolRef(true),
Filters: []ec2.GetAmiFilter{
{
Name: "name",
Values: []string{
"ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-*",
},
},
{
Name: "virtualization-type",
Values: []string{
"hvm",
},
},
},
Owners: []string{
"099720109477",
},
}, nil)
if err != nil {
return err
}
_, err = ec2.NewInstance(ctx, "example", &ec2.InstanceArgs{
Ami: pulumi.String(ubuntu.Id),
InstanceType: pulumi.String(ec2.InstanceType_T3_Micro),
Tags: pulumi.StringMap{
"Name": pulumi.String("HelloWorld"),
},
})
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 ubuntu = Aws.Ec2.GetAmi.Invoke(new()
{
MostRecent = true,
Filters = new[]
{
new Aws.Ec2.Inputs.GetAmiFilterInputArgs
{
Name = "name",
Values = new[]
{
"ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-*",
},
},
new Aws.Ec2.Inputs.GetAmiFilterInputArgs
{
Name = "virtualization-type",
Values = new[]
{
"hvm",
},
},
},
Owners = new[]
{
"099720109477",
},
});
var example = new Aws.Ec2.Instance("example", new()
{
Ami = ubuntu.Apply(getAmiResult => getAmiResult.Id),
InstanceType = Aws.Ec2.InstanceType.T3_Micro,
Tags =
{
{ "Name", "HelloWorld" },
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.ec2.Ec2Functions;
import com.pulumi.aws.ec2.inputs.GetAmiArgs;
import com.pulumi.aws.ec2.Instance;
import com.pulumi.aws.ec2.InstanceArgs;
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) {
final var ubuntu = Ec2Functions.getAmi(GetAmiArgs.builder()
.mostRecent(true)
.filters(
GetAmiFilterArgs.builder()
.name("name")
.values("ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-*")
.build(),
GetAmiFilterArgs.builder()
.name("virtualization-type")
.values("hvm")
.build())
.owners("099720109477")
.build());
var example = new Instance("example", InstanceArgs.builder()
.ami(ubuntu.id())
.instanceType("t3.micro")
.tags(Map.of("Name", "HelloWorld"))
.build());
}
}
resources:
example:
type: aws:ec2:Instance
properties:
ami: ${ubuntu.id}
instanceType: t3.micro
tags:
Name: HelloWorld
variables:
ubuntu:
fn::invoke:
function: aws:ec2:getAmi
arguments:
mostRecent: true
filters:
- name: name
values:
- ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-*
- name: virtualization-type
values:
- hvm
owners:
- '099720109477'
The getAmi data source filters AMIs by name pattern and virtualization type, returning the most recent match. The owners property restricts results to Canonical’s official Ubuntu images. The ami property references the data source output, ensuring the instance always launches with the latest AMI matching your criteria.
Reference AMIs from Systems Manager Parameter Store
AWS publishes AMI IDs to Systems Manager Parameter Store, providing stable paths to official AMI catalogs without requiring data source lookups.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const example = new aws.ec2.Instance("example", {
ami: "resolve:ssm:/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64",
instanceType: aws.ec2.InstanceType.T3_Micro,
tags: {
Name: "HelloWorld",
},
});
import pulumi
import pulumi_aws as aws
example = aws.ec2.Instance("example",
ami="resolve:ssm:/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64",
instance_type=aws.ec2.InstanceType.T3_MICRO,
tags={
"Name": "HelloWorld",
})
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/ec2"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := ec2.NewInstance(ctx, "example", &ec2.InstanceArgs{
Ami: pulumi.String("resolve:ssm:/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64"),
InstanceType: pulumi.String(ec2.InstanceType_T3_Micro),
Tags: pulumi.StringMap{
"Name": pulumi.String("HelloWorld"),
},
})
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.Ec2.Instance("example", new()
{
Ami = "resolve:ssm:/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64",
InstanceType = Aws.Ec2.InstanceType.T3_Micro,
Tags =
{
{ "Name", "HelloWorld" },
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.ec2.Instance;
import com.pulumi.aws.ec2.InstanceArgs;
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 Instance("example", InstanceArgs.builder()
.ami("resolve:ssm:/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64")
.instanceType("t3.micro")
.tags(Map.of("Name", "HelloWorld"))
.build());
}
}
resources:
example:
type: aws:ec2:Instance
properties:
ami: resolve:ssm:/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64
instanceType: t3.micro
tags:
Name: HelloWorld
The ami property uses the resolve:ssm: prefix to fetch the AMI ID from Parameter Store at deployment time. This approach provides stable paths to AWS-managed AMI catalogs (like Amazon Linux 2023) without explicit data source configuration. Your AWS credentials must have permissions to read SSM parameters.
Request spot instances with price limits
Workloads that can tolerate interruption often use spot instances to reduce compute costs by bidding on spare EC2 capacity.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const example = aws.ec2.getAmi({
mostRecent: true,
owners: ["amazon"],
filters: [
{
name: "architecture",
values: ["arm64"],
},
{
name: "name",
values: ["al2023-ami-2023*"],
},
],
});
const exampleInstance = new aws.ec2.Instance("example", {
ami: example.then(example => example.id),
instanceMarketOptions: {
marketType: "spot",
spotOptions: {
maxPrice: "0.0031",
},
},
instanceType: aws.ec2.InstanceType.T4g_Nano,
tags: {
Name: "test-spot",
},
});
import pulumi
import pulumi_aws as aws
example = aws.ec2.get_ami(most_recent=True,
owners=["amazon"],
filters=[
{
"name": "architecture",
"values": ["arm64"],
},
{
"name": "name",
"values": ["al2023-ami-2023*"],
},
])
example_instance = aws.ec2.Instance("example",
ami=example.id,
instance_market_options={
"market_type": "spot",
"spot_options": {
"max_price": "0.0031",
},
},
instance_type=aws.ec2.InstanceType.T4G_NANO,
tags={
"Name": "test-spot",
})
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/ec2"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
example, err := ec2.LookupAmi(ctx, &ec2.LookupAmiArgs{
MostRecent: pulumi.BoolRef(true),
Owners: []string{
"amazon",
},
Filters: []ec2.GetAmiFilter{
{
Name: "architecture",
Values: []string{
"arm64",
},
},
{
Name: "name",
Values: []string{
"al2023-ami-2023*",
},
},
},
}, nil)
if err != nil {
return err
}
_, err = ec2.NewInstance(ctx, "example", &ec2.InstanceArgs{
Ami: pulumi.String(example.Id),
InstanceMarketOptions: &ec2.InstanceInstanceMarketOptionsArgs{
MarketType: pulumi.String("spot"),
SpotOptions: &ec2.InstanceInstanceMarketOptionsSpotOptionsArgs{
MaxPrice: pulumi.String("0.0031"),
},
},
InstanceType: pulumi.String(ec2.InstanceType_T4g_Nano),
Tags: pulumi.StringMap{
"Name": pulumi.String("test-spot"),
},
})
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 = Aws.Ec2.GetAmi.Invoke(new()
{
MostRecent = true,
Owners = new[]
{
"amazon",
},
Filters = new[]
{
new Aws.Ec2.Inputs.GetAmiFilterInputArgs
{
Name = "architecture",
Values = new[]
{
"arm64",
},
},
new Aws.Ec2.Inputs.GetAmiFilterInputArgs
{
Name = "name",
Values = new[]
{
"al2023-ami-2023*",
},
},
},
});
var exampleInstance = new Aws.Ec2.Instance("example", new()
{
Ami = example.Apply(getAmiResult => getAmiResult.Id),
InstanceMarketOptions = new Aws.Ec2.Inputs.InstanceInstanceMarketOptionsArgs
{
MarketType = "spot",
SpotOptions = new Aws.Ec2.Inputs.InstanceInstanceMarketOptionsSpotOptionsArgs
{
MaxPrice = "0.0031",
},
},
InstanceType = Aws.Ec2.InstanceType.T4g_Nano,
Tags =
{
{ "Name", "test-spot" },
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.ec2.Ec2Functions;
import com.pulumi.aws.ec2.inputs.GetAmiArgs;
import com.pulumi.aws.ec2.Instance;
import com.pulumi.aws.ec2.InstanceArgs;
import com.pulumi.aws.ec2.inputs.InstanceInstanceMarketOptionsArgs;
import com.pulumi.aws.ec2.inputs.InstanceInstanceMarketOptionsSpotOptionsArgs;
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) {
final var example = Ec2Functions.getAmi(GetAmiArgs.builder()
.mostRecent(true)
.owners("amazon")
.filters(
GetAmiFilterArgs.builder()
.name("architecture")
.values("arm64")
.build(),
GetAmiFilterArgs.builder()
.name("name")
.values("al2023-ami-2023*")
.build())
.build());
var exampleInstance = new Instance("exampleInstance", InstanceArgs.builder()
.ami(example.id())
.instanceMarketOptions(InstanceInstanceMarketOptionsArgs.builder()
.marketType("spot")
.spotOptions(InstanceInstanceMarketOptionsSpotOptionsArgs.builder()
.maxPrice("0.0031")
.build())
.build())
.instanceType("t4g.nano")
.tags(Map.of("Name", "test-spot"))
.build());
}
}
resources:
exampleInstance:
type: aws:ec2:Instance
name: example
properties:
ami: ${example.id}
instanceMarketOptions:
marketType: spot
spotOptions:
maxPrice: 0.0031
instanceType: t4g.nano
tags:
Name: test-spot
variables:
example:
fn::invoke:
function: aws:ec2:getAmi
arguments:
mostRecent: true
owners:
- amazon
filters:
- name: architecture
values:
- arm64
- name: name
values:
- al2023-ami-2023*
The instanceMarketOptions property configures spot instance behavior. Setting marketType to “spot” requests spare capacity, while maxPrice caps your bid. When spot prices exceed your limit or capacity becomes unavailable, AWS terminates the instance. The example doesn’t configure spotInstanceInterruptionBehavior, so AWS defaults to terminating the instance on interruption.
Attach a pre-existing network interface at launch
Some applications require specific IP addresses or network configuration that must be defined before instance launch, such as when migrating workloads or maintaining consistent network identity.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const myVpc = new aws.ec2.Vpc("my_vpc", {
cidrBlock: "172.16.0.0/16",
tags: {
Name: "tf-example",
},
});
const mySubnet = new aws.ec2.Subnet("my_subnet", {
vpcId: myVpc.id,
cidrBlock: "172.16.10.0/24",
availabilityZone: "us-west-2a",
tags: {
Name: "tf-example",
},
});
const example = new aws.ec2.NetworkInterface("example", {
subnetId: mySubnet.id,
privateIps: ["172.16.10.100"],
tags: {
Name: "primary_network_interface",
},
});
const exampleInstance = new aws.ec2.Instance("example", {
ami: "ami-005e54dee72cc1d00",
instanceType: aws.ec2.InstanceType.T2_Micro,
primaryNetworkInterface: {
networkInterfaceId: example.id,
},
creditSpecification: {
cpuCredits: "unlimited",
},
});
import pulumi
import pulumi_aws as aws
my_vpc = aws.ec2.Vpc("my_vpc",
cidr_block="172.16.0.0/16",
tags={
"Name": "tf-example",
})
my_subnet = aws.ec2.Subnet("my_subnet",
vpc_id=my_vpc.id,
cidr_block="172.16.10.0/24",
availability_zone="us-west-2a",
tags={
"Name": "tf-example",
})
example = aws.ec2.NetworkInterface("example",
subnet_id=my_subnet.id,
private_ips=["172.16.10.100"],
tags={
"Name": "primary_network_interface",
})
example_instance = aws.ec2.Instance("example",
ami="ami-005e54dee72cc1d00",
instance_type=aws.ec2.InstanceType.T2_MICRO,
primary_network_interface={
"network_interface_id": example.id,
},
credit_specification={
"cpu_credits": "unlimited",
})
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/ec2"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
myVpc, err := ec2.NewVpc(ctx, "my_vpc", &ec2.VpcArgs{
CidrBlock: pulumi.String("172.16.0.0/16"),
Tags: pulumi.StringMap{
"Name": pulumi.String("tf-example"),
},
})
if err != nil {
return err
}
mySubnet, err := ec2.NewSubnet(ctx, "my_subnet", &ec2.SubnetArgs{
VpcId: myVpc.ID(),
CidrBlock: pulumi.String("172.16.10.0/24"),
AvailabilityZone: pulumi.String("us-west-2a"),
Tags: pulumi.StringMap{
"Name": pulumi.String("tf-example"),
},
})
if err != nil {
return err
}
example, err := ec2.NewNetworkInterface(ctx, "example", &ec2.NetworkInterfaceArgs{
SubnetId: mySubnet.ID(),
PrivateIps: pulumi.StringArray{
pulumi.String("172.16.10.100"),
},
Tags: pulumi.StringMap{
"Name": pulumi.String("primary_network_interface"),
},
})
if err != nil {
return err
}
_, err = ec2.NewInstance(ctx, "example", &ec2.InstanceArgs{
Ami: pulumi.String("ami-005e54dee72cc1d00"),
InstanceType: pulumi.String(ec2.InstanceType_T2_Micro),
PrimaryNetworkInterface: &ec2.InstancePrimaryNetworkInterfaceArgs{
NetworkInterfaceId: example.ID(),
},
CreditSpecification: &ec2.InstanceCreditSpecificationArgs{
CpuCredits: pulumi.String("unlimited"),
},
})
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 myVpc = new Aws.Ec2.Vpc("my_vpc", new()
{
CidrBlock = "172.16.0.0/16",
Tags =
{
{ "Name", "tf-example" },
},
});
var mySubnet = new Aws.Ec2.Subnet("my_subnet", new()
{
VpcId = myVpc.Id,
CidrBlock = "172.16.10.0/24",
AvailabilityZone = "us-west-2a",
Tags =
{
{ "Name", "tf-example" },
},
});
var example = new Aws.Ec2.NetworkInterface("example", new()
{
SubnetId = mySubnet.Id,
PrivateIps = new[]
{
"172.16.10.100",
},
Tags =
{
{ "Name", "primary_network_interface" },
},
});
var exampleInstance = new Aws.Ec2.Instance("example", new()
{
Ami = "ami-005e54dee72cc1d00",
InstanceType = Aws.Ec2.InstanceType.T2_Micro,
PrimaryNetworkInterface = new Aws.Ec2.Inputs.InstancePrimaryNetworkInterfaceArgs
{
NetworkInterfaceId = example.Id,
},
CreditSpecification = new Aws.Ec2.Inputs.InstanceCreditSpecificationArgs
{
CpuCredits = "unlimited",
},
});
});
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.ec2.Subnet;
import com.pulumi.aws.ec2.SubnetArgs;
import com.pulumi.aws.ec2.NetworkInterface;
import com.pulumi.aws.ec2.NetworkInterfaceArgs;
import com.pulumi.aws.ec2.Instance;
import com.pulumi.aws.ec2.InstanceArgs;
import com.pulumi.aws.ec2.inputs.InstancePrimaryNetworkInterfaceArgs;
import com.pulumi.aws.ec2.inputs.InstanceCreditSpecificationArgs;
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 myVpc = new Vpc("myVpc", VpcArgs.builder()
.cidrBlock("172.16.0.0/16")
.tags(Map.of("Name", "tf-example"))
.build());
var mySubnet = new Subnet("mySubnet", SubnetArgs.builder()
.vpcId(myVpc.id())
.cidrBlock("172.16.10.0/24")
.availabilityZone("us-west-2a")
.tags(Map.of("Name", "tf-example"))
.build());
var example = new NetworkInterface("example", NetworkInterfaceArgs.builder()
.subnetId(mySubnet.id())
.privateIps("172.16.10.100")
.tags(Map.of("Name", "primary_network_interface"))
.build());
var exampleInstance = new Instance("exampleInstance", InstanceArgs.builder()
.ami("ami-005e54dee72cc1d00")
.instanceType("t2.micro")
.primaryNetworkInterface(InstancePrimaryNetworkInterfaceArgs.builder()
.networkInterfaceId(example.id())
.build())
.creditSpecification(InstanceCreditSpecificationArgs.builder()
.cpuCredits("unlimited")
.build())
.build());
}
}
resources:
myVpc:
type: aws:ec2:Vpc
name: my_vpc
properties:
cidrBlock: 172.16.0.0/16
tags:
Name: tf-example
mySubnet:
type: aws:ec2:Subnet
name: my_subnet
properties:
vpcId: ${myVpc.id}
cidrBlock: 172.16.10.0/24
availabilityZone: us-west-2a
tags:
Name: tf-example
example:
type: aws:ec2:NetworkInterface
properties:
subnetId: ${mySubnet.id}
privateIps:
- 172.16.10.100
tags:
Name: primary_network_interface
exampleInstance:
type: aws:ec2:Instance
name: example
properties:
ami: ami-005e54dee72cc1d00
instanceType: t2.micro
primaryNetworkInterface:
networkInterfaceId: ${example.id}
creditSpecification:
cpuCredits: unlimited
The primaryNetworkInterface property attaches a pre-created NetworkInterface resource at launch, giving you control over private IPs, security groups, and subnet placement. The creditSpecification property configures CPU credit behavior for burstable instance types (T2, T3, T4g), setting cpuCredits to “unlimited” to allow sustained high CPU usage beyond baseline performance.
Configure CPU cores and threads for specialized workloads
Certain workloads benefit from custom CPU topology to optimize for performance or meet software licensing requirements that charge per core.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const example = new aws.ec2.Vpc("example", {
cidrBlock: "172.16.0.0/16",
tags: {
Name: "tf-example",
},
});
const exampleSubnet = new aws.ec2.Subnet("example", {
vpcId: example.id,
cidrBlock: "172.16.10.0/24",
availabilityZone: "us-east-2a",
tags: {
Name: "tf-example",
},
});
const amzn_linux_2023_ami = aws.ec2.getAmi({
mostRecent: true,
owners: ["amazon"],
filters: [{
name: "name",
values: ["al2023-ami-2023.*-x86_64"],
}],
});
const exampleInstance = new aws.ec2.Instance("example", {
ami: amzn_linux_2023_ami.then(amzn_linux_2023_ami => amzn_linux_2023_ami.id),
instanceType: aws.ec2.InstanceType.C6a_2XLarge,
subnetId: exampleSubnet.id,
cpuOptions: {
coreCount: 2,
threadsPerCore: 2,
},
tags: {
Name: "tf-example",
},
});
import pulumi
import pulumi_aws as aws
example = aws.ec2.Vpc("example",
cidr_block="172.16.0.0/16",
tags={
"Name": "tf-example",
})
example_subnet = aws.ec2.Subnet("example",
vpc_id=example.id,
cidr_block="172.16.10.0/24",
availability_zone="us-east-2a",
tags={
"Name": "tf-example",
})
amzn_linux_2023_ami = aws.ec2.get_ami(most_recent=True,
owners=["amazon"],
filters=[{
"name": "name",
"values": ["al2023-ami-2023.*-x86_64"],
}])
example_instance = aws.ec2.Instance("example",
ami=amzn_linux_2023_ami.id,
instance_type=aws.ec2.InstanceType.C6A_2_X_LARGE,
subnet_id=example_subnet.id,
cpu_options={
"core_count": 2,
"threads_per_core": 2,
},
tags={
"Name": "tf-example",
})
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/ec2"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
example, err := ec2.NewVpc(ctx, "example", &ec2.VpcArgs{
CidrBlock: pulumi.String("172.16.0.0/16"),
Tags: pulumi.StringMap{
"Name": pulumi.String("tf-example"),
},
})
if err != nil {
return err
}
exampleSubnet, err := ec2.NewSubnet(ctx, "example", &ec2.SubnetArgs{
VpcId: example.ID(),
CidrBlock: pulumi.String("172.16.10.0/24"),
AvailabilityZone: pulumi.String("us-east-2a"),
Tags: pulumi.StringMap{
"Name": pulumi.String("tf-example"),
},
})
if err != nil {
return err
}
amzn_linux_2023_ami, err := ec2.LookupAmi(ctx, &ec2.LookupAmiArgs{
MostRecent: pulumi.BoolRef(true),
Owners: []string{
"amazon",
},
Filters: []ec2.GetAmiFilter{
{
Name: "name",
Values: []string{
"al2023-ami-2023.*-x86_64",
},
},
},
}, nil)
if err != nil {
return err
}
_, err = ec2.NewInstance(ctx, "example", &ec2.InstanceArgs{
Ami: pulumi.String(amzn_linux_2023_ami.Id),
InstanceType: pulumi.String(ec2.InstanceType_C6a_2XLarge),
SubnetId: exampleSubnet.ID(),
CpuOptions: &ec2.InstanceCpuOptionsArgs{
CoreCount: pulumi.Int(2),
ThreadsPerCore: pulumi.Int(2),
},
Tags: pulumi.StringMap{
"Name": pulumi.String("tf-example"),
},
})
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.Ec2.Vpc("example", new()
{
CidrBlock = "172.16.0.0/16",
Tags =
{
{ "Name", "tf-example" },
},
});
var exampleSubnet = new Aws.Ec2.Subnet("example", new()
{
VpcId = example.Id,
CidrBlock = "172.16.10.0/24",
AvailabilityZone = "us-east-2a",
Tags =
{
{ "Name", "tf-example" },
},
});
var amzn_linux_2023_ami = Aws.Ec2.GetAmi.Invoke(new()
{
MostRecent = true,
Owners = new[]
{
"amazon",
},
Filters = new[]
{
new Aws.Ec2.Inputs.GetAmiFilterInputArgs
{
Name = "name",
Values = new[]
{
"al2023-ami-2023.*-x86_64",
},
},
},
});
var exampleInstance = new Aws.Ec2.Instance("example", new()
{
Ami = amzn_linux_2023_ami.Apply(amzn_linux_2023_ami => amzn_linux_2023_ami.Apply(getAmiResult => getAmiResult.Id)),
InstanceType = Aws.Ec2.InstanceType.C6a_2XLarge,
SubnetId = exampleSubnet.Id,
CpuOptions = new Aws.Ec2.Inputs.InstanceCpuOptionsArgs
{
CoreCount = 2,
ThreadsPerCore = 2,
},
Tags =
{
{ "Name", "tf-example" },
},
});
});
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.ec2.Subnet;
import com.pulumi.aws.ec2.SubnetArgs;
import com.pulumi.aws.ec2.Ec2Functions;
import com.pulumi.aws.ec2.inputs.GetAmiArgs;
import com.pulumi.aws.ec2.Instance;
import com.pulumi.aws.ec2.InstanceArgs;
import com.pulumi.aws.ec2.inputs.InstanceCpuOptionsArgs;
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 Vpc("example", VpcArgs.builder()
.cidrBlock("172.16.0.0/16")
.tags(Map.of("Name", "tf-example"))
.build());
var exampleSubnet = new Subnet("exampleSubnet", SubnetArgs.builder()
.vpcId(example.id())
.cidrBlock("172.16.10.0/24")
.availabilityZone("us-east-2a")
.tags(Map.of("Name", "tf-example"))
.build());
final var amzn-linux-2023-ami = Ec2Functions.getAmi(GetAmiArgs.builder()
.mostRecent(true)
.owners("amazon")
.filters(GetAmiFilterArgs.builder()
.name("name")
.values("al2023-ami-2023.*-x86_64")
.build())
.build());
var exampleInstance = new Instance("exampleInstance", InstanceArgs.builder()
.ami(amzn_linux_2023_ami.id())
.instanceType("c6a.2xlarge")
.subnetId(exampleSubnet.id())
.cpuOptions(InstanceCpuOptionsArgs.builder()
.coreCount(2)
.threadsPerCore(2)
.build())
.tags(Map.of("Name", "tf-example"))
.build());
}
}
resources:
example:
type: aws:ec2:Vpc
properties:
cidrBlock: 172.16.0.0/16
tags:
Name: tf-example
exampleSubnet:
type: aws:ec2:Subnet
name: example
properties:
vpcId: ${example.id}
cidrBlock: 172.16.10.0/24
availabilityZone: us-east-2a
tags:
Name: tf-example
exampleInstance:
type: aws:ec2:Instance
name: example
properties:
ami: ${["amzn-linux-2023-ami"].id}
instanceType: c6a.2xlarge
subnetId: ${exampleSubnet.id}
cpuOptions:
coreCount: 2
threadsPerCore: 2
tags:
Name: tf-example
variables:
amzn-linux-2023-ami:
fn::invoke:
function: aws:ec2:getAmi
arguments:
mostRecent: true
owners:
- amazon
filters:
- name: name
values:
- al2023-ami-2023.*-x86_64
The cpuOptions property controls CPU topology. Setting coreCount to 2 and threadsPerCore to 2 creates a 4-vCPU instance (2 cores × 2 threads) from a C6a.2xlarge that normally provides 8 vCPUs. This configuration can reduce licensing costs for per-core software or optimize performance for workloads that benefit from fewer, faster cores.
Beyond these examples
These snippets focus on specific instance-level features: AMI selection (dynamic filters and SSM Parameter Store), spot instances and pricing, and network interface attachment and CPU topology. They’re intentionally minimal rather than full VM deployments.
The examples typically assume pre-existing infrastructure such as VPC, subnets, and security groups, network interfaces (for attachment examples), and IAM permissions for SSM Parameter Store. They focus on configuring the instance rather than provisioning the surrounding infrastructure.
To keep things focused, common instance patterns are omitted, including:
- SSH key pairs and remote access (keyName)
- IAM instance profiles for AWS service access
- User data bootstrapping (userData, userDataBase64)
- EBS volume configuration (rootBlockDevice, ebsBlockDevices)
- Security group configuration (vpcSecurityGroupIds)
- Monitoring, maintenance, and metadata options
These omissions are intentional: the goal is to illustrate how each instance feature is wired, not provide drop-in VM modules. See the EC2 Instance resource reference for all available configuration options.
Let's launch an EC2 Instance
Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.
Try Pulumi Cloud for FREEFrequently Asked Questions
Instance Lifecycle & Updates
userDataReplaceOnChange to true to trigger destroy/recreate instead. Use userDataBase64 for non-UTF-8 data like gzip-compressed scripts to avoid corruption.forceDestroy requires a successful pulumi up after setting it to true and before destroying. It won’t work if set in the same operation that replaces or destroys the instance, or immediately after import without running pulumi up first.ami, availabilityZone, ebsOptimized, ephemeralBlockDevices, hostId, instanceMarketOptions, keyName, launchTemplate, placementGroup, placementGroupId, placementPartitionNumber, privateDnsNameOptions, privateIp, securityGroups, subnetId, tenancy, and associatePublicIpAddress.instanceType triggers a stop/start of the instance, not a replacement.Networking & Security
vpcSecurityGroupIds for VPC instances. The securityGroups parameter is deprecated and forces instance replacement on changes, while vpcSecurityGroupIds allows updates.publicIp attribute reflects the instance’s current public IP, which changes when you attach an EIP. Reference the EIP’s address directly instead of using the instance’s publicIp attribute.networkInterface parameter is deprecated. Use primaryNetworkInterface for the primary interface and aws.ec2.NetworkInterfaceAttachment for additional interfaces.Tagging & Volume Management
volumeTags while managing block device tags outside the Instance resource (e.g., via aws.ebs.Volume tags with aws.ec2.VolumeAttachment) causes resource cycling and inconsistent behavior. Choose one approach for tag management.- Instance tags apply to the instance only, not volumes. 2) Default tags apply to instance and all volumes. 3) Volume tags (
volumeTags) apply to root and EBS volumes at creation. 4) Root block device tags apply only to root volume (conflicts withvolumeTags). 5) EBS block device tags apply to specific EBS volumes (conflicts withvolumeTags).
Dedicated Hosts & Spot Instances
hostResourceGroupArn to your host resource group ARN and either omit tenancy or set it to host.instanceMarketOptions with marketType: "spot" and optionally set spotOptions.maxPrice to your maximum price.AMI Selection
aws.ec2.getAmi data source with filters to find AMIs, or reference AWS Systems Manager Parameter Store with the resolve:ssm:/aws/service/ami-amazon-linux-latest/... syntax.