The aws:gamelift/gameServerGroup:GameServerGroup resource, part of the Pulumi AWS provider, manages a GameLift FleetIQ game server group that provisions and scales EC2 instances for hosting game servers. This guide focuses on four capabilities: instance type definitions and capacity weighting, spot instance balancing strategies, auto-scaling policies with target tracking, and IAM role configuration.
Game server groups require an EC2 launch template that defines the instance configuration and an IAM role that grants GameLift permissions to manage Auto Scaling groups. The examples are intentionally small. Combine them with your own launch templates, VPC configuration, and monitoring.
Create the required IAM role for GameLift access
Before creating a game server group, you need an IAM role that grants GameLift and Auto Scaling permissions to manage EC2 instances.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const current = aws.getPartition({});
const assumeRole = aws.iam.getPolicyDocument({
statements: [{
effect: "Allow",
principals: [{
type: "Service",
identifiers: [
"autoscaling.amazonaws.com",
"gamelift.amazonaws.com",
],
}],
actions: ["sts:AssumeRole"],
}],
});
const example = new aws.iam.Role("example", {
assumeRolePolicy: assumeRole.then(assumeRole => assumeRole.json),
name: "gamelift-game-server-group-example",
});
const exampleRolePolicyAttachment = new aws.iam.RolePolicyAttachment("example", {
policyArn: current.then(current => `arn:${current.partition}:iam::aws:policy/GameLiftGameServerGroupPolicy`),
role: example.name,
});
import pulumi
import pulumi_aws as aws
current = aws.get_partition()
assume_role = aws.iam.get_policy_document(statements=[{
"effect": "Allow",
"principals": [{
"type": "Service",
"identifiers": [
"autoscaling.amazonaws.com",
"gamelift.amazonaws.com",
],
}],
"actions": ["sts:AssumeRole"],
}])
example = aws.iam.Role("example",
assume_role_policy=assume_role.json,
name="gamelift-game-server-group-example")
example_role_policy_attachment = aws.iam.RolePolicyAttachment("example",
policy_arn=f"arn:{current.partition}:iam::aws:policy/GameLiftGameServerGroupPolicy",
role=example.name)
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws"
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/iam"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
current, err := aws.GetPartition(ctx, &aws.GetPartitionArgs{}, nil)
if err != nil {
return err
}
assumeRole, err := iam.GetPolicyDocument(ctx, &iam.GetPolicyDocumentArgs{
Statements: []iam.GetPolicyDocumentStatement{
{
Effect: pulumi.StringRef("Allow"),
Principals: []iam.GetPolicyDocumentStatementPrincipal{
{
Type: "Service",
Identifiers: []string{
"autoscaling.amazonaws.com",
"gamelift.amazonaws.com",
},
},
},
Actions: []string{
"sts:AssumeRole",
},
},
},
}, nil)
if err != nil {
return err
}
example, err := iam.NewRole(ctx, "example", &iam.RoleArgs{
AssumeRolePolicy: pulumi.String(assumeRole.Json),
Name: pulumi.String("gamelift-game-server-group-example"),
})
if err != nil {
return err
}
_, err = iam.NewRolePolicyAttachment(ctx, "example", &iam.RolePolicyAttachmentArgs{
PolicyArn: pulumi.Sprintf("arn:%v:iam::aws:policy/GameLiftGameServerGroupPolicy", current.Partition),
Role: example.Name,
})
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 current = Aws.GetPartition.Invoke();
var assumeRole = Aws.Iam.GetPolicyDocument.Invoke(new()
{
Statements = new[]
{
new Aws.Iam.Inputs.GetPolicyDocumentStatementInputArgs
{
Effect = "Allow",
Principals = new[]
{
new Aws.Iam.Inputs.GetPolicyDocumentStatementPrincipalInputArgs
{
Type = "Service",
Identifiers = new[]
{
"autoscaling.amazonaws.com",
"gamelift.amazonaws.com",
},
},
},
Actions = new[]
{
"sts:AssumeRole",
},
},
},
});
var example = new Aws.Iam.Role("example", new()
{
AssumeRolePolicy = assumeRole.Apply(getPolicyDocumentResult => getPolicyDocumentResult.Json),
Name = "gamelift-game-server-group-example",
});
var exampleRolePolicyAttachment = new Aws.Iam.RolePolicyAttachment("example", new()
{
PolicyArn = $"arn:{current.Apply(getPartitionResult => getPartitionResult.Partition)}:iam::aws:policy/GameLiftGameServerGroupPolicy",
Role = example.Name,
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.AwsFunctions;
import com.pulumi.aws.inputs.GetPartitionArgs;
import com.pulumi.aws.iam.IamFunctions;
import com.pulumi.aws.iam.inputs.GetPolicyDocumentArgs;
import com.pulumi.aws.iam.Role;
import com.pulumi.aws.iam.RoleArgs;
import com.pulumi.aws.iam.RolePolicyAttachment;
import com.pulumi.aws.iam.RolePolicyAttachmentArgs;
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 current = AwsFunctions.getPartition(GetPartitionArgs.builder()
.build());
final var assumeRole = IamFunctions.getPolicyDocument(GetPolicyDocumentArgs.builder()
.statements(GetPolicyDocumentStatementArgs.builder()
.effect("Allow")
.principals(GetPolicyDocumentStatementPrincipalArgs.builder()
.type("Service")
.identifiers(
"autoscaling.amazonaws.com",
"gamelift.amazonaws.com")
.build())
.actions("sts:AssumeRole")
.build())
.build());
var example = new Role("example", RoleArgs.builder()
.assumeRolePolicy(assumeRole.json())
.name("gamelift-game-server-group-example")
.build());
var exampleRolePolicyAttachment = new RolePolicyAttachment("exampleRolePolicyAttachment", RolePolicyAttachmentArgs.builder()
.policyArn(String.format("arn:%s:iam::aws:policy/GameLiftGameServerGroupPolicy", current.partition()))
.role(example.name())
.build());
}
}
resources:
example:
type: aws:iam:Role
properties:
assumeRolePolicy: ${assumeRole.json}
name: gamelift-game-server-group-example
exampleRolePolicyAttachment:
type: aws:iam:RolePolicyAttachment
name: example
properties:
policyArn: arn:${current.partition}:iam::aws:policy/GameLiftGameServerGroupPolicy
role: ${example.name}
variables:
current:
fn::invoke:
function: aws:getPartition
arguments: {}
assumeRole:
fn::invoke:
function: aws:iam:getPolicyDocument
arguments:
statements:
- effect: Allow
principals:
- type: Service
identifiers:
- autoscaling.amazonaws.com
- gamelift.amazonaws.com
actions:
- sts:AssumeRole
The assume role policy allows both gamelift.amazonaws.com and autoscaling.amazonaws.com to assume the role. The GameLiftGameServerGroupPolicy is an AWS-managed policy that grants the necessary permissions for FleetIQ to manage your Auto Scaling group and EC2 instances.
Create a game server group with basic scaling
Game server groups manage fleets of EC2 instances, balancing capacity across instance types while GameLift FleetIQ handles game server placement.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const example = new aws.gamelift.GameServerGroup("example", {
gameServerGroupName: "example",
instanceDefinitions: [
{
instanceType: "c5.large",
},
{
instanceType: "c5a.large",
},
],
launchTemplate: {
id: exampleAwsLaunchTemplate.id,
},
maxSize: 1,
minSize: 1,
roleArn: exampleAwsIamRole.arn,
}, {
dependsOn: [exampleAwsIamRolePolicyAttachment],
});
import pulumi
import pulumi_aws as aws
example = aws.gamelift.GameServerGroup("example",
game_server_group_name="example",
instance_definitions=[
{
"instance_type": "c5.large",
},
{
"instance_type": "c5a.large",
},
],
launch_template={
"id": example_aws_launch_template["id"],
},
max_size=1,
min_size=1,
role_arn=example_aws_iam_role["arn"],
opts = pulumi.ResourceOptions(depends_on=[example_aws_iam_role_policy_attachment]))
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/gamelift"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := gamelift.NewGameServerGroup(ctx, "example", &gamelift.GameServerGroupArgs{
GameServerGroupName: pulumi.String("example"),
InstanceDefinitions: gamelift.GameServerGroupInstanceDefinitionArray{
&gamelift.GameServerGroupInstanceDefinitionArgs{
InstanceType: pulumi.String("c5.large"),
},
&gamelift.GameServerGroupInstanceDefinitionArgs{
InstanceType: pulumi.String("c5a.large"),
},
},
LaunchTemplate: &gamelift.GameServerGroupLaunchTemplateArgs{
Id: pulumi.Any(exampleAwsLaunchTemplate.Id),
},
MaxSize: pulumi.Int(1),
MinSize: pulumi.Int(1),
RoleArn: pulumi.Any(exampleAwsIamRole.Arn),
}, pulumi.DependsOn([]pulumi.Resource{
exampleAwsIamRolePolicyAttachment,
}))
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.GameLift.GameServerGroup("example", new()
{
GameServerGroupName = "example",
InstanceDefinitions = new[]
{
new Aws.GameLift.Inputs.GameServerGroupInstanceDefinitionArgs
{
InstanceType = "c5.large",
},
new Aws.GameLift.Inputs.GameServerGroupInstanceDefinitionArgs
{
InstanceType = "c5a.large",
},
},
LaunchTemplate = new Aws.GameLift.Inputs.GameServerGroupLaunchTemplateArgs
{
Id = exampleAwsLaunchTemplate.Id,
},
MaxSize = 1,
MinSize = 1,
RoleArn = exampleAwsIamRole.Arn,
}, new CustomResourceOptions
{
DependsOn =
{
exampleAwsIamRolePolicyAttachment,
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.gamelift.GameServerGroup;
import com.pulumi.aws.gamelift.GameServerGroupArgs;
import com.pulumi.aws.gamelift.inputs.GameServerGroupInstanceDefinitionArgs;
import com.pulumi.aws.gamelift.inputs.GameServerGroupLaunchTemplateArgs;
import com.pulumi.resources.CustomResourceOptions;
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 GameServerGroup("example", GameServerGroupArgs.builder()
.gameServerGroupName("example")
.instanceDefinitions(
GameServerGroupInstanceDefinitionArgs.builder()
.instanceType("c5.large")
.build(),
GameServerGroupInstanceDefinitionArgs.builder()
.instanceType("c5a.large")
.build())
.launchTemplate(GameServerGroupLaunchTemplateArgs.builder()
.id(exampleAwsLaunchTemplate.id())
.build())
.maxSize(1)
.minSize(1)
.roleArn(exampleAwsIamRole.arn())
.build(), CustomResourceOptions.builder()
.dependsOn(exampleAwsIamRolePolicyAttachment)
.build());
}
}
resources:
example:
type: aws:gamelift:GameServerGroup
properties:
gameServerGroupName: example
instanceDefinitions:
- instanceType: c5.large
- instanceType: c5a.large
launchTemplate:
id: ${exampleAwsLaunchTemplate.id}
maxSize: 1
minSize: 1
roleArn: ${exampleAwsIamRole.arn}
options:
dependsOn:
- ${exampleAwsIamRolePolicyAttachment}
The instanceDefinitions array lists EC2 instance types that GameLift can use. The launchTemplate references your EC2 launch template that defines AMI, security groups, and user data. The minSize and maxSize properties set Auto Scaling boundaries. The roleArn must reference the IAM role created in the previous example, and the dependsOn ensures the role policy attachment completes before creating the group.
Configure spot instances with auto-scaling policies
Production deployments often use spot instances to reduce costs while maintaining target utilization through auto-scaling.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const example = new aws.gamelift.GameServerGroup("example", {
autoScalingPolicy: {
estimatedInstanceWarmup: 60,
targetTrackingConfiguration: {
targetValue: 75,
},
},
balancingStrategy: "SPOT_ONLY",
gameServerGroupName: "example",
gameServerProtectionPolicy: "FULL_PROTECTION",
instanceDefinitions: [
{
instanceType: "c5.large",
weightedCapacity: "1",
},
{
instanceType: "c5.2xlarge",
weightedCapacity: "2",
},
],
launchTemplate: {
id: exampleAwsLaunchTemplate.id,
version: "1",
},
maxSize: 1,
minSize: 1,
roleArn: exampleAwsIamRole.arn,
tags: {
Name: "example",
},
vpcSubnets: [
"subnet-12345678",
"subnet-23456789",
],
}, {
dependsOn: [exampleAwsIamRolePolicyAttachment],
});
import pulumi
import pulumi_aws as aws
example = aws.gamelift.GameServerGroup("example",
auto_scaling_policy={
"estimated_instance_warmup": 60,
"target_tracking_configuration": {
"target_value": 75,
},
},
balancing_strategy="SPOT_ONLY",
game_server_group_name="example",
game_server_protection_policy="FULL_PROTECTION",
instance_definitions=[
{
"instance_type": "c5.large",
"weighted_capacity": "1",
},
{
"instance_type": "c5.2xlarge",
"weighted_capacity": "2",
},
],
launch_template={
"id": example_aws_launch_template["id"],
"version": "1",
},
max_size=1,
min_size=1,
role_arn=example_aws_iam_role["arn"],
tags={
"Name": "example",
},
vpc_subnets=[
"subnet-12345678",
"subnet-23456789",
],
opts = pulumi.ResourceOptions(depends_on=[example_aws_iam_role_policy_attachment]))
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/gamelift"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := gamelift.NewGameServerGroup(ctx, "example", &gamelift.GameServerGroupArgs{
AutoScalingPolicy: &gamelift.GameServerGroupAutoScalingPolicyArgs{
EstimatedInstanceWarmup: pulumi.Int(60),
TargetTrackingConfiguration: &gamelift.GameServerGroupAutoScalingPolicyTargetTrackingConfigurationArgs{
TargetValue: pulumi.Float64(75),
},
},
BalancingStrategy: pulumi.String("SPOT_ONLY"),
GameServerGroupName: pulumi.String("example"),
GameServerProtectionPolicy: pulumi.String("FULL_PROTECTION"),
InstanceDefinitions: gamelift.GameServerGroupInstanceDefinitionArray{
&gamelift.GameServerGroupInstanceDefinitionArgs{
InstanceType: pulumi.String("c5.large"),
WeightedCapacity: pulumi.String("1"),
},
&gamelift.GameServerGroupInstanceDefinitionArgs{
InstanceType: pulumi.String("c5.2xlarge"),
WeightedCapacity: pulumi.String("2"),
},
},
LaunchTemplate: &gamelift.GameServerGroupLaunchTemplateArgs{
Id: pulumi.Any(exampleAwsLaunchTemplate.Id),
Version: pulumi.String("1"),
},
MaxSize: pulumi.Int(1),
MinSize: pulumi.Int(1),
RoleArn: pulumi.Any(exampleAwsIamRole.Arn),
Tags: pulumi.StringMap{
"Name": pulumi.String("example"),
},
VpcSubnets: pulumi.StringArray{
pulumi.String("subnet-12345678"),
pulumi.String("subnet-23456789"),
},
}, pulumi.DependsOn([]pulumi.Resource{
exampleAwsIamRolePolicyAttachment,
}))
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.GameLift.GameServerGroup("example", new()
{
AutoScalingPolicy = new Aws.GameLift.Inputs.GameServerGroupAutoScalingPolicyArgs
{
EstimatedInstanceWarmup = 60,
TargetTrackingConfiguration = new Aws.GameLift.Inputs.GameServerGroupAutoScalingPolicyTargetTrackingConfigurationArgs
{
TargetValue = 75,
},
},
BalancingStrategy = "SPOT_ONLY",
GameServerGroupName = "example",
GameServerProtectionPolicy = "FULL_PROTECTION",
InstanceDefinitions = new[]
{
new Aws.GameLift.Inputs.GameServerGroupInstanceDefinitionArgs
{
InstanceType = "c5.large",
WeightedCapacity = "1",
},
new Aws.GameLift.Inputs.GameServerGroupInstanceDefinitionArgs
{
InstanceType = "c5.2xlarge",
WeightedCapacity = "2",
},
},
LaunchTemplate = new Aws.GameLift.Inputs.GameServerGroupLaunchTemplateArgs
{
Id = exampleAwsLaunchTemplate.Id,
Version = "1",
},
MaxSize = 1,
MinSize = 1,
RoleArn = exampleAwsIamRole.Arn,
Tags =
{
{ "Name", "example" },
},
VpcSubnets = new[]
{
"subnet-12345678",
"subnet-23456789",
},
}, new CustomResourceOptions
{
DependsOn =
{
exampleAwsIamRolePolicyAttachment,
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.gamelift.GameServerGroup;
import com.pulumi.aws.gamelift.GameServerGroupArgs;
import com.pulumi.aws.gamelift.inputs.GameServerGroupAutoScalingPolicyArgs;
import com.pulumi.aws.gamelift.inputs.GameServerGroupAutoScalingPolicyTargetTrackingConfigurationArgs;
import com.pulumi.aws.gamelift.inputs.GameServerGroupInstanceDefinitionArgs;
import com.pulumi.aws.gamelift.inputs.GameServerGroupLaunchTemplateArgs;
import com.pulumi.resources.CustomResourceOptions;
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 GameServerGroup("example", GameServerGroupArgs.builder()
.autoScalingPolicy(GameServerGroupAutoScalingPolicyArgs.builder()
.estimatedInstanceWarmup(60)
.targetTrackingConfiguration(GameServerGroupAutoScalingPolicyTargetTrackingConfigurationArgs.builder()
.targetValue(75.0)
.build())
.build())
.balancingStrategy("SPOT_ONLY")
.gameServerGroupName("example")
.gameServerProtectionPolicy("FULL_PROTECTION")
.instanceDefinitions(
GameServerGroupInstanceDefinitionArgs.builder()
.instanceType("c5.large")
.weightedCapacity("1")
.build(),
GameServerGroupInstanceDefinitionArgs.builder()
.instanceType("c5.2xlarge")
.weightedCapacity("2")
.build())
.launchTemplate(GameServerGroupLaunchTemplateArgs.builder()
.id(exampleAwsLaunchTemplate.id())
.version("1")
.build())
.maxSize(1)
.minSize(1)
.roleArn(exampleAwsIamRole.arn())
.tags(Map.of("Name", "example"))
.vpcSubnets(
"subnet-12345678",
"subnet-23456789")
.build(), CustomResourceOptions.builder()
.dependsOn(exampleAwsIamRolePolicyAttachment)
.build());
}
}
resources:
example:
type: aws:gamelift:GameServerGroup
properties:
autoScalingPolicy:
estimatedInstanceWarmup: 60
targetTrackingConfiguration:
targetValue: 75
balancingStrategy: SPOT_ONLY
gameServerGroupName: example
gameServerProtectionPolicy: FULL_PROTECTION
instanceDefinitions:
- instanceType: c5.large
weightedCapacity: '1'
- instanceType: c5.2xlarge
weightedCapacity: '2'
launchTemplate:
id: ${exampleAwsLaunchTemplate.id}
version: '1'
maxSize: 1
minSize: 1
roleArn: ${exampleAwsIamRole.arn}
tags:
Name: example
vpcSubnets:
- subnet-12345678
- subnet-23456789
options:
dependsOn:
- ${exampleAwsIamRolePolicyAttachment}
The balancingStrategy set to SPOT_ONLY uses only spot instances. The autoScalingPolicy defines target tracking that scales the group to maintain 75% utilization. The weightedCapacity property lets you assign different capacity values to instance types (c5.2xlarge counts as 2 units). The gameServerProtectionPolicy set to FULL_PROTECTION prevents termination of instances running active game servers. The vpcSubnets property places instances in specific subnets for network isolation.
Beyond these examples
These snippets focus on specific game server group features: instance type definitions and weighted capacity, spot instance balancing and cost optimization, and IAM role configuration for GameLift access. They’re intentionally minimal rather than full game hosting deployments.
The examples reference pre-existing infrastructure such as EC2 launch templates and VPC subnets for production configurations. They focus on configuring the game server group rather than provisioning the surrounding infrastructure.
To keep things focused, common game server group patterns are omitted, including:
- Launch template configuration (AMI, user data, security groups)
- Game server protection during scale-down events
- VPC subnet selection and availability zone distribution
- Custom auto-scaling metrics beyond target tracking
These omissions are intentional: the goal is to illustrate how each game server group feature is wired, not provide drop-in game hosting modules. See the GameLift GameServerGroup resource reference for all available configuration options.
Let's configure AWS GameLift Game Server Groups
Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.
Try Pulumi Cloud for FREEFrequently Asked Questions
IAM & Permissions
autoscaling.amazonaws.com and gamelift.amazonaws.com to assume the role, plus the AWS managed policy GameLiftGameServerGroupPolicy attached.dependsOn to ensure the policy attachment completes first.Instance Protection & Scaling
NO_PROTECTION (default) allows instances with active game servers to be terminated during scale-down, potentially dropping players. FULL_PROTECTION prevents termination while game servers are active, except during forced deletion.SPOT_ONLY, SPOT_PREFERRED (default), or ON_DEMAND_ONLY. This controls how GameLift FleetIQ balances instance types.weightedCapacity assigns a capacity weight to each instance type, allowing larger instances to count for more capacity units during scaling. For example, a c5.2xlarge with weight 2 counts as two c5.large instances with weight 1.Configuration & Immutability
gameServerGroupName, maxSize, minSize, autoScalingPolicy, or vpcSubnets after creation. These require resource replacement.vpcSubnets, GameLift FleetIQ uses all supported Availability Zones by default.launchTemplate configuration accepts both id and an optional version parameter.