T-family vs. M-family: picking the right instance for variable load
T instances are usually the first thing anyone reaches for: a dev box, a low-traffic API, a jump box. They’re cheaper than M-family at the same size, and for workloads that sit idle most of the time, that’s the whole story. But T instances don’t give you a full dedicated vCPU — they give you a fraction of one plus a credit balance for bursts, and once that balance runs out you’re either throttled or billed extra. For the mechanics of how CPU credits are earned and spent, and the exact crossover math against M-series, see The burstable CPU credit trap. This guide is the shorter version: how to decide, in one pass, whether T or M is the right pick for a given workload.
CPU credits in three sentences
Every T instance earns CPU credits continuously and spends them when it needs more than its baseline share of a vCPU. T3 and T4g run in Unlimited mode by default, so when credits run out the instance doesn’t throttle — it keeps running at full speed and AWS bills the overage at $0.05 per vCPU-hour. That’s fine for a workload that spikes occasionally and idles the rest of the time; it’s a problem for a workload that sits at moderate-to-high CPU all day, because the overage charges stack up quietly in the background. The blog post linked above has the full accounting and the exact crossover percentage for each T size.
What T actually costs less than M, today
Here’s the on-demand baseline comparison — no bursting, no surplus charges, just the sticker price — for us-east-1 Linux, using the $/vCPU-hr and $/GiB-hr convention from Right-sizing with $/vCPU-hr and $/GiB-hr:
| Instance | vCPU | Memory (GiB) | Price/hr | $/vCPU-hr | $/GiB-hr |
|---|---|---|---|---|---|
| t3.large | 2 | 8 | $0.0832 | $0.0416 | $0.0104 |
| m6i.large | 2 | 8 | $0.0960 | $0.0480 | $0.0120 |
| m7i.large | 2 | 8 | $0.1008 | $0.0504 | $0.0126 |
| t3.xlarge | 4 | 16 | $0.1664 | $0.0416 | $0.0104 |
| m6i.xlarge | 4 | 16 | $0.1920 | $0.0480 | $0.0120 |
| m7i.xlarge | 4 | 16 | $0.2016 | $0.0504 | $0.0126 |
| t4g.large | 2 | 8 | $0.0672 | $0.0336 | $0.0084 |
| m6g.large | 2 | 8 | $0.0770 | $0.0385 | $0.0096 |
| m7g.large | 2 | 8 | $0.0816 | $0.0408 | $0.0102 |
| t4g.xlarge | 4 | 16 | $0.1344 | $0.0336 | $0.0084 |
| m6g.xlarge | 4 | 16 | $0.1540 | $0.0385 | $0.0096 |
| m7g.xlarge | 4 | 16 | $0.1632 | $0.0408 | $0.0102 |
At equal vCPU and memory, t3.large is 13% cheaper than m6i.large and 17% cheaper than m7i.large. t4g.large is 13% cheaper than m6g.large and 18% cheaper than m7g.large. That’s the discount you’re being paid to take on the credit-accounting model — it’s real and it’s consistent across sizes within a generation. It’s also strictly a baseline-load number: it says nothing about what happens once your CPU usage climbs, which is the whole subject of the blog post above.
M-family doesn’t sell a size below large (2 vCPU, 8 GiB), so there’s no direct M equivalent for t3.micro, t3.small, or t3.medium — those small T sizes are effectively unmatched territory, cheap because nothing else is that small, not because of the burstable discount specifically.
Is this workload bursty enough for T?
Run through this before defaulting to T or M:
Good fits for T (t3 / t4g):
- Dev and staging boxes that sit idle nights and weekends
- Low-traffic internal APIs and admin dashboards
- Bastion hosts and jump boxes — near-zero CPU most of the time
- CI runners for short, infrequent jobs (not a continuous build queue)
- Cron jobs that run briefly and go back to idle
Bad fits for T (use M instead):
- Services with sustained average CPU above roughly 40%
- Background workers that process a continuous queue, not a bursty one
- Production databases, caches, and message brokers
- Anything with a strict latency SLA where credit-driven or noisy-neighbor variance is a risk
- Batch jobs that run CPU-bound for hours at a stretch
If you’re not sure which bucket a workload falls into, that’s a sign you don’t have utilization data yet — get it before picking either family. A rough average from CloudWatch over a week of real traffic beats a guess.
The Unlimited mode risk, briefly
T3 and T4g run in Unlimited mode by default, so a credit-exhausted instance doesn’t fail — it keeps serving traffic and quietly bills surplus credits at $0.05/vCPU-hour. That’s the safe failure mode for a dev box and the expensive failure mode for a production service, because nothing stops the bill from climbing until someone notices. Each T size has a specific sustained-CPU percentage above which the surplus charges make it more expensive than the equivalent M instance; the blog post walks through that math and lists the crossover point for each common size. If you can’t say with any confidence what your average sustained CPU is, treat that as a reason to check CPUSurplusCreditCharged in CloudWatch before committing to T for anything beyond a dev environment.
Making the call
Stay on T. Idle-most-of-the-time workloads: dev, staging, bastions, low-traffic internal tools, short CI jobs. The 13-18% baseline discount is free money as long as sustained CPU stays low.
Move to M. Anything averaging above roughly 40% CPU, anything running a continuous queue or batch job, and any production database, cache, or broker. Compare specific sizes in the instance explorer or side by side in the comparison tool — the M-family page for a given size (families/m7i, families/m7g) shows the full size range.
Not sure yet. Start on T, watch CPUCreditBalance and CPUSurplusCreditCharged in CloudWatch for a week of real traffic, and let the data answer the question instead of the sticker price. A workload that looked bursty in staging can turn out to run hot in production, and the credit metrics will tell you before the invoice does.
Bottom line: T instances are 13-18% cheaper than M at the same size, but only at baseline load — the discount assumes your CPU usage stays under what the instance earns in credits. If a workload is genuinely idle most of the time, take the discount. If it’s a steady, CPU-hungry service, skip straight to M and skip the guesswork.