EC2: Instance Types, Families, and When a VM Is Still the Right Answer
A Hundred Names for the Same Idea
Open EC2's "Launch instance" screen for the first time and you're handed a search box in front of several hundred rows: t3.micro, t4g.small, m6i.large, m6g.xlarge, c7g.2xlarge, r6i.4xlarge, and on. Most tutorials tell you to pick t2.micro or t3.medium and move on, which is fine advice for a five-minute experiment and genuinely bad advice for anything that has to run in production for a year. Every one of those names is a real, specific answer to three separate questions: what kind of workload is this instance shaped for, which generation of AWS's hardware is it running on, and how much of it do you want. Reading the name is a skill, not trivia, because guessing wrong on any of the three costs actual money every month it keeps running.
An earlier lesson in this collection, on how the cloud actually works, already covered the mechanics one level down: renting somewhere else's computer, and a vCPU being a hyperthread rather than a full physical core. Assume that here rather than re-deriving it. This lesson goes the other direction, up from the hardware into the actual product: EC2's catalogue of instance types, how the names are constructed, what genuinely differs between an instance you're offered and the next one over, and, at the end, whether reaching for a virtual machine at all is still the right call once containers and serverless functions exist as real alternatives.
Reading an Instance Type's Name
An instance type name has a fixed grammar, even though it looks like an arbitrary product code. Take m6g.large apart. m is the family, and it says what the instance is shaped for - in this case, general purpose, a roughly even balance of compute and memory. 6 is the generation, AWS's version number for that family's underlying hardware. g is an attribute letter, and here it means the processor is AWS's own Graviton chip, which is ARM rather than the x86 architecture most people default to assuming. Everything after the dot, large, is the size: how many vCPUs and how much memory that specific slice comes with, following a fixed ratio the family defines.
A few more attribute letters show up often enough to know on sight. a means the processor is AMD rather than Intel, which is usually a small discount for close to the same performance. n means enhanced networking, a bigger network pipe attached to the same compute. d means the instance comes with local NVMe storage physically attached to the host, on top of whatever network-attached storage gets added separately. AWS adds new attribute letters as new hardware ships, so this isn't an exhaustive list - when a name has a letter that doesn't match any of these, the instance types page for that family is the source of truth, not a guess.
aws ec2 describe-instance-types \
--instance-types m6g.large \
--query 'InstanceTypes[0].{vCPUs:VCpuInfo.DefaultVCpus,MemoryMiB:MemoryInfo.SizeInMiB,Network:NetworkInfo.NetworkPerformance}'
# {
# "vCPUs": 2,
# "MemoryMiB": 8192,
# "Network": "Up to 12500 Megabit"
# }That's the habit worth building. Guessing specs from a name is optional - the API will state them exactly, for any instance type, in one command, which is faster and more reliable than remembering a table.
The Families, by What They Trade Off
Every family holds the same vCPU-to-memory ratio across its whole size range, and that ratio is the actual product being sold, not a marketing label. A general purpose (M) instance gives roughly 4 GiB of memory per vCPU, which suits a typical web application or API server that's neither especially CPU-hungry nor especially memory-hungry. Move the ratio up toward memory and you get the R family, built for things that hold a lot of data in RAM at once: an in-memory cache, a large database's working set, a JVM with a big heap. Move it down toward compute and you get the C family: batch processing, video encoding, anything that's waiting on the processor rather than on RAM or the network.
Two more shapes exist for workloads the ratio-based families don't fit. Storage-optimized instances (I and D) trade the balanced ratio for very fast local disk - high-IOPS NVMe for I, dense HDD capacity for D - aimed at databases and distributed filesystems that are bottlenecked on disk rather than CPU or memory. Accelerated computing instances (P, G, and the newer purpose-built Inferentia and Trainium families) attach GPUs or dedicated ML chips instead of relying on the general-purpose processor at all, for model training and inference workloads a CPU handles too slowly to be worth the wait.
The burstable T family - t3, t4g, and the free-tier-eligible defaults most tutorials reach for - was already covered in the earlier lesson on how the cloud actually works: those instances aren't sold a steady share of the processor, they accumulate CPU credits while idle and spend them under load, and running out mid-traffic-spike is a genuinely common production incident. That's still true here, and worth reading if you haven't.
Sizes Scale in a Straight Line
Within a family, size is close to arithmetic: large is the baseline, xlarge roughly doubles vCPU and memory, 2xlarge doubles again, and so on, up to whatever the family's largest offered size is. The ratio the family defines holds at every size, so an m6g.xlarge is two m6g.large instances' worth of compute and memory in one machine, not a different shape. That property is what makes capacity planning tractable: if a workload needs twice the throughput, the size directly above usually does the job, without having to re-derive which family fits.
The catch is that doubling size doubles the price at roughly the same rate, because you're renting more of the same host, not getting a bulk discount on the sticker price. Bulk discounts exist in AWS's pricing model, but they come from commitment, not from size - the purchase options an earlier lesson on cloud costs already covered (Savings Plans, Reserved Instances, Spot) apply the same way whether the instance is a large or a 4xlarge.
Generations Exist Because the Hardware Underneath Keeps Changing
The generation number matters more than it looks like it should. AWS periodically replaces the physical hardware behind a family with newer processors, and each generation is generally faster and cheaper per unit of compute than the one before it - which means an old instance sitting in a long-running account is very often leaving performance and money on the table at the same time, not trading one for the other. Checking whether a newer generation of the same family exists, and whether it's a drop-in replacement, is a five-minute task worth doing periodically rather than never.
The one generation change that isn't a drop-in replacement is a move to Graviton, the g attribute. Graviton is ARM, and an x86 binary doesn't run on it. Most managed language runtimes, and most things installed from a package manager, will simply rebuild for the new architecture without incident - but a codebase with compiled dependencies, custom native extensions, or a Docker base image pinned to linux/amd64 needs an explicit multi-architecture build before Graviton is an option, not just a configuration change. That's the actual reason "just switch to Graviton, it's cheaper" is sometimes a one-line change and sometimes a real migration.
What Actually Boots
An instance doesn't start from nothing. It starts from an AMI - an Amazon Machine Image - a saved, bootable copy of a root volume: the operating system, and anything baked into that image beforehand. AWS publishes AMIs for common operating systems, the AWS Marketplace has vendor-published ones, and it's possible to build one from a configured instance so a fleet launches already set up rather than being provisioned from scratch every time.
Storage on an instance comes in two genuinely different kinds, and confusing them causes real data loss. An EBS-backed root volume is network-attached storage that persists independently of the instance - stop the instance, and the volume, and whatever's on it, is still there, still billing separately, when it starts again. Instance store volumes are physically attached NVMe disks on that specific host, and they're wiped the moment the instance stops or gets moved onto different hardware - they survive a reboot, not a stop. Instance store is faster because there's no network hop to it, which is exactly why it's tempting to put a database's data directory there. Don't, unless the loss is something you've deliberately built for.
The Pricing Model Was Already Covered - Here's What's Specific to EC2
An earlier lesson on what the cloud actually costs already worked through the general purchasing spectrum - on-demand, Savings Plans, Reserved Instances, Spot - and that reasoning applies to EC2 unchanged, so it isn't repeated here. Two things are specific to EC2 itself and worth knowing on top of it. Billing is per second, with a 60-second minimum, for Linux on-demand and Spot instances - Windows and some Marketplace AMIs still bill by the hour, worth checking before assuming a short-lived instance costs almost nothing.
The other is what actually happens when a Spot instance gets reclaimed. AWS gives a two-minute interruption warning, delivered to the instance's own metadata endpoint and as an EventBridge event, before taking the instance back - not zero warning, but not long enough to do anything by hand. Anything running on Spot in production needs to poll for that warning and checkpoint or hand off work automatically inside those two minutes, or Spot isn't actually saving money, it's just moving the cost into incident response.
Where People Actually Lose Money and Time
A handful of mistakes account for most of the wasted spend and the middle-of-the-night pages. Oversizing "to be safe" is the most common and the easiest to avoid - the size-doubling relationship from earlier means a guess that's one size too big isn't a small buffer, it's paying for twice the machine, indefinitely, for a margin that monitoring would have told you whether you actually needed. Picking a family by habit rather than by workload shape is close behind: a CPU-bound batch job on a memory-optimized R instance pays for RAM it never touches, and a workload that genuinely needs memory on a general-purpose M instance quietly swaps or gets OOM-killed under load an R instance of the right size would have absorbed without noticing.
A stopped instance is not a free instance. Stopping an EC2 instance stops the compute charge, but the attached EBS volumes keep billing, and an Elastic IP address that isn't attached to a running instance bills separately, specifically because it's sitting idle and reserved. Long-running accounts accumulate stopped instances and orphaned Elastic IPs the same way the cloud-costs lesson described orphaned resources in general - nobody deletes what nobody's actively looking at.
And the burstable-instance credit trap from the earlier lesson deserves a second mention here specifically, because it's most often hit for exactly this reason: someone right-sizes a workload correctly, picks the cheapest instance that handles average load, and that instance happens to be a T-family one, and average load is not peak load. The fix isn't "don't use T instances" - they're genuinely the right economic choice for spiky, low-average workloads - it's knowing which category the workload is in before picking the family, not after the pager goes off.
When a VM Is Still the Right Answer
An earlier lesson comparing virtual machines, containers, and serverless already laid out the general decision: containers when the goal is portability and fast, consistent deploys without owning a kernel; serverless when the work is short, event-shaped, and there's no reason to think about a running instance at all; a VM when neither of those fits. What follows is what specifically points back to a VM once you're choosing at the EC2 level rather than in the abstract.
Reach for EC2 directly when the workload needs something a container can't give: kernel modules, a custom kernel version, direct hardware access, or software licensed per physical or virtual machine in a way a container's shared kernel doesn't satisfy. GPU-heavy training jobs that run for hours or days are usually a better fit for a long-running EC2 instance than for a function with a timeout measured in minutes. Steady, predictable, always-on workloads are where Reserved Instances and Savings Plans make EC2 cheaper than the equivalent serverless spend, because provisioned-capacity pricing is being paid for capacity that was always going to be used anyway. There's a genuine edge case at the far end of the catalogue, too: EC2 Mac instances are the only way to get a real macOS build agent from a cloud provider at all, because Apple's license terms require Apple hardware - a constraint no container or function can route around.
Reach for something else when the workload is the opposite of steady - short, spiky, event-triggered work is exactly what serverless pricing is built for, and paying for an EC2 instance sitting mostly idle between events is paying for capacity that mostly isn't used. And reach for containers over raw EC2 when the actual goal is portability and fast, repeatable deploys across environments - the VM is still there underneath a container host, but the unit being managed day to day should usually be the smaller one, unless something specific pulls the decision back up to the instance level.
What to Take Away
An instance type name is a specification, not a label: family for the shape, generation for the hardware, attribute letters for what's bolted on, size for the raw amount. Getting comfortable reading it, and comfortable reaching for the API instead of guessing, replaces a lot of trial and error with five minutes of lookup. The bigger judgment call sits one level up from any of that: whether the workload wants a full machine at all, or would be cheaper and simpler as a container or a function instead. EC2 is the right tool for a real, specific, and shrinking set of reasons - it's just that the reasons that remain are ones nothing else substitutes for.
Further reading
- Amazon EC2 Instance TypesThe current catalogue, family by family, straight from AWS.
- AWS Graviton ProcessorsAWS's own case for ARM migration, and what it changes underneath.
- EC2 Spot Instance InterruptionsExactly how the two-minute interruption warning is delivered.
- Amazon EC2 Instance StoreWhat's ephemeral, what isn't, and why the difference is easy to miss.
- Amazon EC2 On-Demand PricingPer-second billing details, by family and operating system.