An Amazon Machine Image (AMI) is the template an instance boots from: a root volume snapshot plus launch metadata. Working with AMIs from the SDK means three jobs - finding the right base image, baking your own from a configured instance, and sharing it with other accounts.
This page walks each job with runnable code, then covers the cleanup that keeps AMIs from quietly costing money.
Never hardcode an AMI id. Ids differ per region and change every time AWS publishes a new build. Instead, resolve the latest official image from an SSM public parameter, which AWS maintains as a stable pointer to the current AMI id.
# --- Python (boto3) ---import boto3ssm = boto3.client("ssm", region_name="us-east-1")param = ssm.get_parameter( Name="/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64",)ami_id = param["Parameter"]["Value"]print(ami_id) # ami-0... current Amazon Linux 2023 for this region
// --- TypeScript (AWS SDK v3) ---import { SSMClient, GetParameterCommand } from "@aws-sdk/client-ssm";const ssm = new SSMClient({ region: "us-east-1" });const param = await ssm.send(new GetParameterCommand({ Name: "/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64",}));const amiId = param.Parameter?.Value;console.log(amiId); // ami-0... current Amazon Linux 2023 for this region
The SSM parameter always points at the newest official build, so the same code returns the right id in every region and after every AWS refresh.
When you need to search rather than resolve a known pointer, use DescribeImages with an Owners list and Filters. The catch: it returns matches in no guaranteed order, so you must sort by CreationDate yourself to get the newest.
Owners: ["amazon"] restricts the search to AWS-published images; use ["self"] for your own, or a 12-digit account id for images shared with you. Without an owner filter the call scans every public AMI, which is slow and rarely what you want.
To create your own AMI, configure an instance the way you want it, then call CreateImage. AWS snapshots the instance's EBS volumes and registers a new AMI that references those snapshots. The new instance you launch from it boots pre-configured.
# --- Python (boto3) ---import boto3ec2 = boto3.client("ec2", region_name="us-east-1")resp = ec2.create_image( InstanceId="i-0abc123", Name="web-app-2026-07-23", Description="Baked web app image", NoReboot=False, # let AWS reboot for a consistent snapshot TagSpecifications=[{ "ResourceType": "image", "Tags": [{"Key": "app", "Value": "web"}], }],)new_ami = resp["ImageId"]ec2.get_waiter("image_available").wait(ImageIds=[new_ami])print("ready:", new_ami)
NoReboot: false (the default) lets AWS reboot the instance so the file system is quiesced and the snapshot is consistent. Set it to true only if you cannot tolerate the reboot and have flushed data yourself - an inconsistent AMI can boot into a corrupt state. The AMI is not usable until it reaches available, so wait on image_available / waitUntilImageAvailable.
An AMI is private to its owner by default. To let another account launch from it, add that account to the image's launchPermission with ModifyImageAttribute.
Sharing the AMI shares its metadata, but the underlying EBS snapshots must be shared too, and if the snapshots are encrypted the target account also needs access to the KMS key. For a truly public image you can set LaunchPermission to a group of all, but do that only for images you intend everyone to use.
Deregistering an AMI with DeregisterImage removes the image but leaves its backing snapshots behind, and snapshots bill by the gigabyte-month. Full cleanup is two steps: deregister the AMI, then delete each snapshot with DeleteSnapshot. Read the snapshot ids from the AMI's BlockDeviceMappings before you deregister.
Hardcoding AMI ids. Ids are region-specific and change on every AWS refresh. Resolve from SSM parameters or DescribeImages, never a literal string checked into code.
Not sorting DescribeImages results. The API returns matches unordered; without sorting by CreationDate you may pick an old build.
NoReboot: true on a busy instance. Skipping the reboot can capture an inconsistent file system and produce an AMI that boots broken.
Deregister-and-forget.DeregisterImage leaves snapshots that keep billing. Delete the snapshots too.
Sharing the AMI but not the snapshot. The target account sees the image but cannot launch it until the snapshots (and any KMS key) are shared.
Launching before available. A freshly created AMI is pending; launching from it fails until it reaches available.
EC2 Image Builder automates a build-test-distribute pipeline for AMIs on a schedule, better than hand-calling CreateImage for repeatable golden images.
Packer (HashiCorp) builds AMIs from a declarative template in CI, decoupled from a live running instance.
User data / configuration management (cloud-init, Ansible) configures a stock AMI at boot instead of baking a custom one, trading launch time for image simplicity.
Bake a custom AMI when boot-time configuration is too slow or fragile; resolve a stock AMI and configure at launch when images change often.
Read the SSM public parameter /aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64 with GetParameter. It always points at the current build for that region.
Why should I not hardcode an AMI id?
Ids are region-specific and change whenever AWS publishes a new image. A hardcoded id breaks in another region and goes stale over time. Resolve it at runtime instead.
How do I find the newest image from DescribeImages?
DescribeImages returns matches in no defined order, so sort the results by CreationDate descending and take the first element.
What does CreateImage actually create?
A new AMI plus EBS snapshots of the instance's volumes. Instances launched from the AMI boot from copies of those snapshots.
What does NoReboot do?
When false (the default) AWS reboots the instance to capture a consistent snapshot. Setting it true skips the reboot but risks an inconsistent, possibly unbootable image.
How do I share an AMI with another account?
Call ModifyImageAttribute to add the account id to LaunchPermission, and also share the backing snapshots (and KMS key if encrypted).
How do I wait until a new AMI is usable?
Use the image_available waiter in boto3 or waitUntilImageAvailable in SDK v3. The AMI is pending until AWS finishes creating the snapshots.
Does deregistering an AMI delete its snapshots?
No. DeregisterImage removes only the image. The backing snapshots remain and keep billing until you delete them with DeleteSnapshot.
Can I copy an AMI to another region?
Yes, with CopyImage, which creates a new AMI and snapshots in the target region. Copy is also how you re-encrypt an AMI with a different KMS key.
What owner values can I filter on?
amazon for AWS images, self for your own, aws-marketplace for Marketplace products, or a 12-digit account id for images shared with you.