Skip to content
ExponaBLOG
AWS FOR DEVELOPERS · DAY 017 / 100

Launch templates: what every AWS developer should know

Versioned instance configuration.

Expona Admin8 min read

Launch templates

If you've been manually configuring EC2 instances across multiple environments, you know how error-prone that process becomes. Launch templates solve this by giving you a versioned, reusable configuration that captures your AMI, instance type, security groups, user data, and dozens of other settings in one place. Think of them as infrastructure-as-code for instance configuration, and they're now essential for working with modern AWS features like Auto Scaling Groups, mixed instance policies, and Spot Fleet.

Why launch templates matter

Before launch templates, you had two options: launch instances manually (inconsistent and unmaintainable) or use launch configurations (immutable, no versioning, deprecated). Launch templates changed that. They let you version every change, roll back easily, and share standardized configurations across teams. More importantly, they're required if you want to use Spot instances, mixed instance types, or advanced Auto Scaling features introduced after 2017.

In my experience building e-commerce and SaaS platforms, launch templates became the foundation for everything else. Once we standardized on them, onboarding new services and spinning up environments became predictable. We could version control our infrastructure decisions just like code.

AMI, instance type, security groups, and user data

A launch template bundles together the core building blocks of an EC2 instance. Let's break down each component and see how they fit together.

Selecting your AMI

The Amazon Machine Image is your instance's operating system and base software. You can use AWS-provided AMIs (Amazon Linux 2, Ubuntu, Windows Server), community AMIs, or your own custom AMIs. In a launch template, you reference the AMI by ID, not name, because IDs don't change across regions.

Here's a practical tip: store your custom AMI ID as a parameter in Systems Manager Parameter Store or in your infrastructure-as-code tool. Hardcoding AMI IDs directly in launch templates makes them brittle.

Instance type flexibility

The instance type determines CPU, memory, and network capacity. A single launch template can support multiple instance types, which becomes crucial when you're using mixed instance policies or want fallback options if capacity runs out.

For example, if you specify t3.large as your primary type, you might also allow t3a.large, t4g.large (Graviton), or older generation types as alternatives. This flexibility keeps costs predictable and prevents Auto Scaling Group failures when AWS runs out of capacity for your first choice.

Security groups for network access

Security groups control inbound and outbound traffic. In a launch template, you reference security groups by ID (or name if in the default VPC, though ID is more reliable). You can specify multiple security groups, which is useful when you need to layer different access policies—one for application traffic, one for monitoring, one for inter-service communication.

A common pattern in my projects: create a security group for each "role" an instance might play (web server, API backend, database client), then reference the relevant ones in your launch template. This keeps rules organized and makes auditing easier.

User data for instance startup

User data is a script that runs when an instance first launches. It's the most common way to bootstrap configuration—installing software, pulling code, starting services. You can pass it as plain text or base64-encoded.

Here's a realistic example for a Node.js application:

bash
#!/bin/bash
set -e
yum update -y
yum install -y nodejs
aws s3 cp s3://my-bucket/app.zip /opt/app.zip
cd /opt
unzip -q app.zip
npm ci --production
npm run migrate
systemctl start myapp

Keep user data scripts idempotent—they should work correctly if run multiple times. Include error handling and logging. Store longer scripts in S3 and reference them, rather than embedding them directly in the launch template.

Version every change

This is where launch templates shine. Every time you modify a template, AWS creates a new numbered version. You can use version 1, 2, 3, or specify $Latest to always reference the newest one. This gives you several powerful capabilities.

Rolling back is straightforward

If version 5 of your template introduces a problem, you don't edit it and create version 6. Instead, you either point your Auto Scaling Group back to version 4, or launch new instances from version 4 while the broken ones drain. No need to recreate the entire configuration.

Audit trail and documentation

Each version captures a snapshot of your instance configuration at a point in time. When you look at a launch template version, you see exactly what security groups, user data, and storage settings were in place. This is invaluable for troubleshooting and compliance.

Gradual rollouts

You can create a new version, test it with a small Auto Scaling Group or spot check an instance, and only promote it to production after validation. Infrastructure changes become safer and more deliberate.

In practice, I version a launch template whenever I change user data, security groups, or instance configuration. I use a naming convention like MyApp-LaunchTemplate-v1 and store the version number in my infrastructure code so it's auditable.

Mixed instances and Spot support

Launch templates unlock two cost-optimization features that weren't available with launch configurations: mixed instance policies and Spot instances.

Mixed instance policies

A mixed instance policy lets an Auto Scaling Group launch a blend of instance types. You define a primary type and a list of alternatives, then set weights so the ASG knows how many instances equal one "unit" of capacity.

For example:

  • t3.large = 1 unit (primary)
  • t3a.large = 1 unit
  • t4g.large = 1 unit
  • m6i.large = 2 units (more powerful, worth 2 small instances)

The ASG tries to launch from your preferred list but automatically falls back if capacity is constrained. This reduces launch failures and keeps costs down by using cheaper alternatives when available.

Spot instance integration

Launch templates are required for Spot instances in modern Auto Scaling configurations. With Spot, you bid on spare EC2 capacity at a discount, accepting the tradeoff that AWS can reclaim the instance with two minutes' notice. Combined with On-Demand as a fallback, Spot can cut your compute costs by 50–70%.

A mixed instance policy with Spot works like this:

  • Launch 70% of instances as Spot (cheaper, interruptible)
  • Launch 30% as On-Demand (stable, reliable)
  • If a Spot instance is reclaimed, the ASG automatically replaces it

Your application needs to be stateless or have quick graceful shutdown to make this work, but if it does, the savings are significant. In a ride-hailing or e-commerce backend with proper connection pooling, this is often straightforward.

Required for modern ASG features

AWS deprecated launch configurations and moved all new features to launch templates. If you want to use these capabilities, launch templates are mandatory:

  • Spot instances and mixed policies – No launch configuration support
  • Multiple network interfaces – Only in launch templates
  • T3 Unlimited mode – Requires launch templates
  • Detailed monitoring and CPU credits configuration – Launch template only
  • Capacity Rebalancing – ASG feature for proactively replacing underutilized Spot instances, requires launch templates
  • Warm pools – Pre-initialized instances ready to scale in, requires launch templates

If you're starting a new project or modernizing an existing one, there's no reason to use launch configurations. AWS has signaled they're the legacy path.

Creating and managing launch templates in practice

Here's a workflow I follow in real projects:

  1. Define launch template parameters (AMI ID, instance type, security groups) in infrastructure-as-code (Terraform, CloudFormation, CDK)
  2. Version control the configuration files, not AWS console clicks
  3. Test new versions by launching a single instance or small test ASG
  4. Reference the template in your Auto Scaling Group, specifying version $Latest or a pinned version
  5. When you need to update (new AMI, different security group), create a new template version and roll out gradually

Using Terraform, it looks roughly like this:

bash
resource "aws_launch_template" "app" {
  name_prefix   = "app-"
  image_id      = var.ami_id
  instance_type = "t3.large"
  
  vpc_security_group_ids = [aws_security_group.app.id]
  
  user_data = base64encode(templatefile("${path.module}/user_data.sh", {
    app_version = var.app_version
  }))
  
  tag_specifications {
    resource_type = "instance"
    tags = {
      Name = "MyApp"
      Environment = var.environment
    }
  }
}

resource "aws_autoscaling_group" "app" {
  name                = "app-asg"
  vpc_zone_identifier = var.subnet_ids
  
  min_size         = 2
  max_size         = 10
  desired_capacity = 3
  
  mixed_instances_policy {
    launch_template {
      launch_template_specification {
        launch_template_id = aws_launch_template.app.id
        version            = "$Latest"
      }
      
      overrides = [
        { instance_type = "t3.large" },
        { instance_type = "t3a.large" },
        { instance_type = "t4g.large" },
      ]
    }
    
    instances_distribution {
      on_demand_base_capacity                  = 1
      on_demand_percentage_above_base_capacity = 30
      spot_instance_pools                      = 3
    }
  }
}

This defines a launch template with sensible defaults and an ASG that uses 70% Spot and 30% On-Demand across three instance types. The $Latest reference means any new template version is picked up automatically for future scale-out events.

Common mistakes

  • Hardcoding AMI IDs – They vary by region and change when you rebuild. Use Parameter Store or reference them in your infrastructure code.
  • Not setting version to $Latest – If you pin to version 1 and create version 2, new instances still use version 1. Use $Latest unless you have a specific reason to pin.
  • Embedding large user data scripts directly – Keep them under 16 KB. For larger configurations, download scripts from S3 in user data.
  • Ignoring instance type compatibility – Don't mix incompatible architectures (x86 and Graviton) without testing. Different instance families have different performance characteristics.
  • Not making user data idempotent – If an instance fails to start and ASG launches a retry, user data runs again. Ensure it works the second time.
  • Forgetting to test new template versions before production rollout – Always validate with a single instance or test ASG first.

Key takeaways

  • Launch templates replace launch configurations and are required for Spot instances, mixed instance policies, and modern ASG features.
  • They capture your AMI, instance type, security groups, and user data in a versioned, reusable configuration.
  • Every change creates a new version automatically, giving you a rollback strategy and audit trail.
  • Use mixed instance policies and Spot instances to optimize costs without sacrificing availability.
  • Always version control your launch template definitions; never rely on AWS console changes as your source of truth.
  • Test new template versions before rolling them out to production, and use $Latest to ensure new instances use the current configuration.
ShareXLinkedInReddit

Found this useful? Support the writing.

Buy me a coffee
Written by
Expona Admin
Site administrator

Comments

Loading comments…

Leave a comment

Comments are reviewed before they appear. Be kind and stay on topic.

Related articles