EC2 Instance Types Explained: How to Choose the Right One for Your Workload
Choosing the wrong EC2 instance type is one of the most common and quietly expensive mistakes in AWS deployments. Engineers often default to whatever they used last, or pick the cheapest option, only to discover weeks later that their application is CPU-throttled, memory-starved, or paying for resources it never touches. Understanding what each EC2 instance family actually means — and why the distinction matters — is the foundation of cost-efficient, performant infrastructure.
TL;DR: EC2 Instance Type Selection at a Glance
| Family | Optimized For | Typical Use Case |
|---|---|---|
| t3 / t4g | Burstable CPU | Dev/test, low-traffic web apps |
| m5 / m6i / m7i | Balanced CPU + Memory | General-purpose web applications, app servers |
| c5 / c6i / c7g | Compute-intensive | High-traffic APIs, batch processing, encoding |
| r5 / r6i / r7g | Memory-intensive | In-memory caches, large databases, analytics |
| i3 / i4i | High I/O (NVMe SSD) | NoSQL databases, data warehousing |
| p4 / g5 | GPU compute | ML training, inference, graphics rendering |
| inf2 / trn1 | ML inference/training | Deep learning at scale |
How EC2 Instance Naming Works
Before selecting an EC2 instance type, you need to decode the naming convention. AWS encodes the family, generation, processor variant, and size into a compact string. Reading it correctly eliminates most of the confusion.
e.g. c7g.2xlarge"] --> B["Family: c
Compute Optimized"] A --> C["Generation: 7
7th Gen Hardware"] A --> D["Processor: g
AWS Graviton3"] A --> E["Size: 2xlarge
8 vCPU / 16 GiB RAM"]
- Family letter(s) — the workload optimization class (t, m, c, r, i, p, g, inf, trn)
- Generation number — higher is newer; newer generations typically offer better price-performance (e.g., m6i vs. m5)
- Processor/attribute suffix —
a= AMD EPYC,g= AWS Graviton (ARM),i= Intel Ice Lake,n= higher network bandwidth,d= local NVMe storage,z= high sustained clock speed - Size — nano, micro, small, medium, large, xlarge, 2xlarge, and so on. Each size step roughly doubles vCPU and memory.
Think of the instance name like a car model code: the letters tell you the vehicle class, the number tells you the model year, and the suffix tells you the engine variant. A c7g.2xlarge is a compute-optimized, 7th-generation, Graviton3-powered instance with 8 vCPUs and 16 GiB RAM.
EC2 Instance Families Explained
T Family — Burstable Performance
The T family (t3, t3a, t4g) operates on a CPU credit model. Instances accumulate credits when CPU utilization stays below a baseline, then spend those credits during bursts. This makes them cost-effective for workloads with low average CPU but occasional spikes — think a staging environment, a low-traffic WordPress site, or a development server.
The critical failure mode engineers hit: running a T-family instance under sustained CPU load. Once credits are exhausted, the instance throttles to its baseline CPU percentage. If you're running a production web application that regularly hits 40–60% CPU, a T instance will silently degrade. The CloudWatch metric CPUCreditBalance dropping to zero is the observable signal. At that point, you're not getting the CPU you're paying for.
T instances also support unlimited mode, which allows sustained bursting beyond the credit balance at an additional per-vCPU-hour charge. This removes the throttling risk but can generate unexpected costs if left unchecked on a busy instance.
M Family — General Purpose
The M family (m5, m6i, m6a, m6g, m7i, m7g) provides a balanced ratio of vCPU to memory — typically 4 GiB per vCPU. This is the right default for most production web application tiers where you don't have a clear CPU or memory bottleneck. App servers, microservices, and mid-tier databases all fit here.
When in doubt, start with M. It's not the cheapest option, but it's the least likely to create a hidden bottleneck. You can always right-size after observing real traffic patterns with CloudWatch metrics and AWS Compute Optimizer recommendations.
C Family — Compute Optimized
The C family (c5, c6i, c6a, c6g, c7g) offers a higher vCPU-to-memory ratio — roughly 2 GiB per vCPU. Choose C when your application is CPU-bound: high-request-rate APIs, video transcoding, scientific simulations, or CPU-intensive batch jobs.
A common misdiagnosis: engineers see high CPU on an M instance and immediately scale horizontally. Before adding more instances, check whether the workload is genuinely CPU-bound or whether it's waiting on I/O, database queries, or external calls. Only the former benefits from moving to C-family.
R Family — Memory Optimized
The R family (r5, r6i, r6a, r6g, r7g) inverts the C family's ratio — roughly 8 GiB per vCPU. Use R when your application needs to hold large datasets in memory: Redis or Memcached clusters, in-memory analytics, large JVM heap applications, or RDS instances with large working sets.
Memory pressure is often misread as CPU pressure. If you see high CPU on an M instance but the application is a JVM service with frequent GC pauses, the real problem is heap exhaustion causing GC thrash — not compute shortage. Moving to R-family and increasing heap size often resolves what looks like a CPU problem.
I Family — Storage Optimized
The I family (i3, i3en, i4i) provides high-throughput local NVMe SSD storage with very low latency. These are purpose-built for I/O-intensive workloads: Cassandra, MongoDB, Elasticsearch, or any database that benefits from local storage rather than EBS-attached volumes.
Important distinction: local NVMe storage on I-family instances is ephemeral. Data does not persist across instance stop/start cycles. This is a hard architectural constraint — design your data layer accordingly with replication or snapshots.
G and P Families — GPU Instances
G-family instances (g4dn, g5) include NVIDIA GPUs suited for ML inference, graphics workloads, and game streaming. P-family instances (p3, p4d) are designed for large-scale ML training with higher GPU memory and NVLink interconnects. Inf2 and Trn1 instances use AWS-designed Inferentia and Trainium chips, respectively, optimized for deep learning inference and training at lower cost than GPU instances for those specific workloads.
How to Choose the Right EC2 Instance Type for a Web Application
For a simple web application, the decision tree is narrower than it appears. Most web applications are I/O-bound at the network and database layer, not CPU or memory bound at the application tier. The instance type decision should be driven by observed metrics, not assumptions.
Instance Selection"]) --> Q1{"Do you have
production traffic data?"} Q1 -->|No| M["Start with M-family
m6i.large or m6g.large"] Q1 -->|Yes| Q2{"Run Compute Optimizer
What is the bottleneck?"} Q2 -->|CPU-bound| C["C-family
c6i / c7g"] Q2 -->|Memory-bound| R["R-family
r6i / r7g"] Q2 -->|Balanced| M2["M-family
m6i / m7g"] Q2 -->|Low avg CPU
spiky traffic| T["T-family
t3 / t4g — dev/test only"] M --> ARM{"Stack supports
ARM64?"} M2 --> ARM C --> ARM R --> ARM ARM -->|Yes| Graviton["Prefer g-suffix variant
for price-performance"] ARM -->|No| Intel["Use i or a suffix
x86 variants"]
- Start with M-family for new deployments. Without production traffic data, a balanced instance avoids premature optimization. An
m6i.largeorm6g.largeis a reasonable starting point for a single-tier web application. - Enable detailed CloudWatch monitoring. Default EC2 monitoring reports metrics at 5-minute intervals. Detailed monitoring reduces this to 1 minute, which is necessary to catch short CPU bursts that average out over 5 minutes.
- Run AWS Compute Optimizer. After 14 days of metric data, Compute Optimizer analyzes CPU, memory (requires CloudWatch agent), network, and disk utilization to recommend right-sized instance types. This is the most reliable signal for right-sizing decisions.
- Avoid T-family for sustained production traffic. If your web application serves consistent traffic throughout the day, the credit model creates unpredictable performance. Reserve T-family for dev/test or genuinely spiky workloads with long idle periods.
- Consider Graviton (g-suffix) for cost savings. AWS Graviton3-based instances (m7g, c7g, r7g) typically offer better price-performance than equivalent x86 instances for most web workloads. Verify your runtime and dependencies support ARM64 before migrating.
Experience Signal: The Misdiagnosed Memory Leak
A production Node.js API running on t3.medium instances started showing intermittent 502 errors under moderate load. The on-call engineer saw CPU at 100% in CloudWatch and assumed a compute bottleneck — the natural conclusion. The team scaled horizontally, adding two more t3.medium instances behind the ALB. The 502s continued.
The actual signal was in the CPUCreditBalance metric, which had been at zero for six hours before the 502s started. The instances weren't CPU-bound in the traditional sense — they had exhausted their burst credits and were throttled to the t3.medium baseline of 20% CPU. The application's event loop was starved, not the hardware.
The fix wasn't more instances — it was moving to m6i.large, which provides consistent, non-throttled CPU. The 502s stopped immediately. Three t3.medium instances under credit exhaustion delivered less effective compute than one m6i.large at steady state. The lesson: CPUCreditBalance must be part of every T-family alarm strategy, not an afterthought.
Depth Signal: Graviton and the x86 Assumption
A non-obvious interaction exists between instance generation selection and Auto Scaling Group launch templates. If you define a launch template with a specific AMI built for x86 (e.g., an Amazon Linux 2 AMI with architecture x86_64) and then change the instance type to a Graviton variant (e.g., m7g.large), the ASG will fail to launch instances with an InvalidAMIID.NotFound or architecture mismatch error — not a clear "wrong architecture" message in all cases.
The ordering dependency that breaks common assumptions: you must update the AMI in the launch template to an ARM64-compatible AMI before or simultaneously with changing the instance type. Updating the instance type first and the AMI second creates a window where the ASG attempts to launch incompatible combinations, which can silently fail during a scale-out event under load — exactly when you need new capacity most.
Key CLI Commands for Instance Type Research
Before committing to an instance type, use the EC2 describe APIs to verify availability and specifications in your target region.
# List all instance types available in a region with vCPU and memory details
aws ec2 describe-instance-types \
--region us-east-1 \
--filters "Name=instance-type,Values=m6i.*" \
--query 'InstanceTypes[*].{Type:InstanceType,vCPU:VCpuInfo.DefaultVCpus,MemGiB:MemoryInfo.SizeInMiB}' \
--output table
# Check instance type offerings (availability) in specific AZs
aws ec2 describe-instance-type-offerings \
--region us-east-1 \
--location-type availability-zone \
--filters "Name=instance-type,Values=m6g.large,m7g.large" \
--query 'InstanceTypeOfferings[*].{Type:InstanceType,AZ:Location}' \
--output table
# Get Compute Optimizer recommendations for EC2 instances
aws compute-optimizer get-ec2-instance-recommendations \
--region us-east-1 \
--query 'instanceRecommendations[*].{Instance:instanceArn,Finding:finding,RecommendedType:recommendationOptions[0].instanceType}' \
--output table
# Check CPUCreditBalance for a T-family instance
aws cloudwatch get-metric-statistics \
--region us-east-1 \
--namespace AWS/EC2 \
--metric-name CPUCreditBalance \
--dimensions Name=InstanceId,Value=i-0123456789abcdef0 \
--start-time 2024-01-01T00:00:00Z \
--end-time 2024-01-01T06:00:00Z \
--period 300 \
--statistics Minimum \
--output table
IAM Permissions Required
To run the CLI commands above, the calling principal needs the following minimum permissions. Read and List actions on EC2 and Compute Optimizer require "Resource": "*" as these actions do not support resource-level restrictions.
🔽 Click to expand — IAM policy for instance type research
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "EC2InstanceTypeResearch",
"Effect": "Allow",
"Action": [
"ec2:DescribeInstanceTypes",
"ec2:DescribeInstanceTypeOfferings"
],
"Resource": "*"
},
{
"Sid": "ComputeOptimizerRead",
"Effect": "Allow",
"Action": [
"compute-optimizer:GetEC2InstanceRecommendations"
],
"Resource": "*"
},
{
"Sid": "CloudWatchMetricsRead",
"Effect": "Allow",
"Action": [
"cloudwatch:GetMetricStatistics"
],
"Resource": "*"
}
]
}
Choosing the Right EC2 Instance Type: Wrap-Up and Next Steps
For a simple web application, the practical path is: start with M-family, instrument with CloudWatch (including the CloudWatch agent for memory metrics), and let Compute Optimizer guide right-sizing after two weeks of real traffic. Avoid T-family for production unless the workload is genuinely bursty with long idle periods. Consider Graviton variants once your stack is validated on ARM64 — the price-performance improvement is real and well-documented.
The instance type decision is not permanent. AWS makes it straightforward to change instance types on stopped instances, and launch template versioning in Auto Scaling Groups allows controlled rollouts. Treat the initial selection as a hypothesis, not a commitment.
- AWS EC2 Instance Types — Official Reference
- AWS Compute Optimizer
- EC2 Pricing — always verify current rates
Glossary
| Term | Definition |
|---|---|
| CPU Credit | A unit of burstable CPU capacity earned by T-family instances when running below baseline utilization, spent during CPU bursts. |
| vCPU | Virtual CPU — a hyperthread of a physical CPU core allocated to an EC2 instance. |
| Graviton | AWS-designed ARM64 processors (Graviton2, Graviton3) used in the g-suffix instance variants, offering competitive price-performance for most general workloads. |
| Compute Optimizer | An AWS service that analyzes CloudWatch utilization metrics and recommends right-sized EC2 instance types based on observed workload patterns. |
| Instance Family | A grouping of EC2 instance types sharing the same workload optimization class (e.g., compute, memory, storage), identified by the leading letter(s) in the instance name. |
Comments
Post a Comment