Savings Plans & Cost Optimisation
Owner: ali@jodapp.com · Baseline captured: 2026-07-04 · Progress re-read: 2026-07-19
(read-only ali-claude profile, account 140151801565, ap-southeast-1) · Basis: full on-demand
list price.
This document is the source of truth for how JOD reduces its AWS bill. It is paired with the live Infrastructure Map. Read the map first if you have not — this page is the money side of the same picture.
Bottom line up front
We can cut the AWS bill from ~$2,925/mo to as low as ~$1,777/mo (‑39%) — but the order of steps
matters more than any single discount. A boss-ready spreadsheet of every payment option lives in
jod-aws-savings-proposal.xlsx.
On-demand list total: EC2 compute $1,128 + RDS $1,059.84 + storage/network/other $722.54 ≈ $2,925/mo (~$35k/yr). This reconciles with the NDS May invoice (202605000003, $2,895.42 after their 2% discount) — i.e. this is what you already pay. All rates are exact: on-demand + RDS RI from the AWS Pricing / RDS-offerings APIs, EC2 Compute SP from the Savings Plans offering-rates API (the same data as the public compute-pricing page), 2026-07-04.
| Plan | What you do | Monthly bill | You save | Upfront cash |
|---|---|---|---|---|
| A — Rightsize | Data-driven Graviton right-sizing across the fleet. No commitment. | $2,505 | $420 (14%) | $0 |
| B — 1yr No-Upfront | A + 1yr Compute SP + 1yr RDS RIs | $2,146 | $779 (27%) | $0 |
| B2 — 1yr All-Upfront | A + 1yr commitments, prepaid | $2,079 | $846 (29%) | $12,452 |
| C2 — 3yr Partial | A + 3yr commitments, ~half prepaid | $1,798 | $1,127 (39%) | $13,606 |
| C — 3yr All-Upfront | A + 3yr commitments, prepaid | $1,777 | $1,148 (39%) | $26,478 |
Recommended: Plan B (right-size + 1-year No-Upfront). It captures 68% of the maximum monthly saving with zero upfront cash and no 3-year lock. Paying $12,452 upfront (B2) buys only $67/mo more — a weak ~6% return on that cash. The lever that is big is the term: 3-year (C/C2) nearly doubles the discount for +$348–369/mo. Take Plan B now; move stable databases + compute to 3-year later, once self-serve and confident.
Where the savings come from — EC2 vs RDS
The totals above combine two independent tracks — EC2 (right-sizing + a Compute Savings Plan) and RDS (Reserved Instances). Neither depends on the other, so you can approve them separately:
| Savings source | 1yr No-Upfront | 1yr All-Upfront | 3yr Partial | 3yr All-Upfront |
|---|---|---|---|---|
| EC2 — right-size (no commitment) | $420 | $420 | $420 | $420 |
| EC2 — Compute Savings Plan | $154 | $181 | $306 | $311 |
| EC2 subtotal | $574 | $601 | $726 | $731 |
| RDS — Reserved Instances | $205 | $245 | $401 | $417 |
| Combined (both) | $779 | $846 | $1,127 | $1,148 |
Two things stand out. Right-sizing alone ($420/mo, free, no commitment) is the single biggest line — larger than any reservation. And because of it, EC2 is ~64–74% of the total while RDS Reserved Instances, though the largest commitment lever, are the smaller share. If you only did one track: EC2 alone saves $574–731/mo, RDS alone saves $205–417/mo.
The biggest free win is Plan A. You do not need a savings plan to get the first $365/mo — you just need to stop running two 8-vCPU servers at 1% CPU.
Progress — what has been captured
Banked so far: $442/mo ($5,300/yr), with zero commitment and zero upfront cash. For scale: Plan A —
the entire free right-sizing track — was projected at $420/mo, and the work done so far has already passed
it, through a mix of right-sizing ($408/mo) and waste cleanup ($34/mo), before the NDS exit and
before buying a single reservation. The monthly bill has moved from ~$2,925 → ~$2,483 (‑15%).
Like-for-like re-read using the same method as the baseline (AWS Pricing API, on-demand list,
ap-southeast-1). The 2026-07-04 fleet of 25 running instances prices at $1,128.03/mo; the current
fleet of 20 prices at $720.11/mo (as of 2026-07-19). The rebuilt baseline lands on the originally
recorded $1,128 to the cent, so the delta is exact, not estimated. Terminations verified in the EC2
console: JodProDockerDemoV2 (i-0c8157fc58198ed7d), jodpro.qa.api (i-002eab88bab149f5c),
jodpro.prod.api (i-010d60d4391b6efd6), jodpro.qa.frontend (i-09dee24623b2275f2),
jodpro.prod.frontend (i-07dab87c96077fee2).
EC2 compute — $1,128.03 → $720.11 (‑$407.92/mo, ‑36%)
| What changed | Before | After | Saved $/mo |
|---|---|---|---|
jodgig.prod.api-2 right-sized | c7g.2xlarge (16 GB) | c7g.large (4 GB) | 182.43 |
jodpro.prod.frontend terminated | c6g.large | — | 57.23 |
jodpro.prod.api terminated | c6g.large | — | 57.23 |
jodpro.qa.frontend terminated | t4g.medium | — | 30.95 |
jodpro.qa.api terminated | t4g.medium | — | 30.95 |
jodgig.prod.reports right-sized | c7g.large (4 GB) | t4g.medium (4 GB) | 29.86 |
JodProDockerDemoV2 terminated | t3.small | — | 19.27 |
| EC2 total | 1,128.03 | 720.11 | 407.92 |
Two results worth reporting upward:
api-2beat the plan — but is still $29.86/mo overpriced. The plan called fort4g.xlarge($123.81) and deliberately kept 16 GB of RAM, because no memory metrics existed and we refused to guess. Moving it toc7g.large(4 GB) banked $182.43/mo — $63/mo more than the plan projected. It is not the right landing spot, though:c7g.largeandt4g.mediumare both 2 vCPU / 4 GB, andc7g.largecosts twice as much ($60.81 vs $30.95). The only thing that premium buys is 2.0 vCPU sustained instead of a 0.4 vCPU burstable baseline — andapi-2draws 0.0058 vCPU. See the API pair analysis below.- Retiring
jodprobeat right-sizing it. The plan proposed shrinking the fourjodproboxes tot4gtargets for $83.52/mo. Terminating them outright banked $176.36/mo — more than double — plus $19.27 for the demo box. The cheapest server is the one that does not run, and no right-sizing exercise can beat deleting a workload that nobody needs.
Waste and databases — ‑$33.65/mo
| What changed | Saved $/mo |
|---|---|
jodpro RDS database terminated (db.t4g.micro · mysql) | 18.25 |
4 idle Elastic IPs released (18.136.1.40, 54.251.205.44, 54.254.14.30, 54.251.52.130) | 14.60 |
JODv2-REPORT-PROD-CRON-env terminated, disk released | 0.80 |
| Subtotal | 33.65 |
Where the bill stands
| Monthly | vs baseline | |
|---|---|---|
| Baseline 2026-07-04 (on-demand list) | $2,925 | — |
| Today (2026-07-19) | ~$2,483 | ‑$442 (‑15%) |
| After the remaining free work below (no commitment) | ~$2,149 | ‑$776 (‑27%) |
| After Plan B on top (1yr No-Upfront SP + RDS RIs) | ~$1,864 | ‑$1,061 (‑36%) |
The bottom two rows are forward projections re-based on the current fleet, not the 2026-07-04 one: fully right-sized EC2 lands at $386.20/mo (from $720.11 today), of which the always-on production baseline is $301.06/mo (a 1yr No-Upfront Compute SP at 27.7% ≈ $83/mo), and the five surviving prod databases on 1yr No-Upfront RIs save $201/mo. The Plan B figure differs from the tables above because the fleet those tables describe no longer exists — you already deleted part of it, and the right-sizing targets are now driven by measured memory rather than the conservative RAM-preserving guesses.
Still available, still free — ~$335/mo
No commitment, no upfront cash, no architecture change:
| Action | Saves $/mo | Status |
|---|---|---|
jodgig.prod.api-3 c7g.2xlarge → t4g.medium | 212.29 | Open — highest-value action left |
jodgig.prod.api-2 c7g.large → t4g.medium | 29.86 | Open — finish the job started on 07-16 |
jodgig.prod.frontend c7g.large → t4g.medium | 29.86 | Open — RAM unchanged (4 GB → 4 GB) |
jodgig.qa.api t4g.medium → t4g.small | 15.48 | Open |
jodgig.qa.frontend t4g.medium → t4g.small | 15.48 | Open |
jodgig.prod.frontend-board + jodgig.qa.frontend-board terminated | 30.96 | Planned |
Delete unattached volume vol-06c22cfc8ea0349cb (8 GB gp3, idle since 2024-08-05) | 0.77 | Open |
jodgig.prod.reports (c7g.large → t4g.medium, $29.86/mo) was on this list and is now done — see the
EC2 compute table above.
The API pair — the largest remaining win ($242.15/mo)
api-2 + api-3 cost $304.05/mo today. Both belong on t4g.medium — $61.90 for the pair, saving
$242.15/mo, which is two-thirds of everything left on the table.
Method — why percentages lie. CloudWatch CPUUtilization is a percentage of the whole instance, so
the same workload reports a different number on every instance size. The doc's original "api-2 p95 0.19%"
meant 0.19% of 8 vCPUs = 0.0152 vCPU absolute; on a 2-vCPU box that identical work reads as 0.76%.
Always convert to absolute vCPU (% × vCPU) before comparing across sizes. A t4g.medium earns 24
credits/hr on 2 vCPUs, which is a 0.4 vCPU sustained baseline — that is the number to compare against.
CloudWatch 30 days to 2026-07-16, converted to absolute vCPU. api-2: 0.0058 vCPU mean (1.5% of a
t4g.medium baseline). api-3: 0.2185 vCPU mean, 0.343 p95, 1.03 peak 1-hr. Memory measured directly
via htop on api-3 under production load: ~1 GB — so t4g.medium's 4 GB is 4× the working set.
Baselines and credit rates from the AWS burstable credit table
(t4g.medium: 2 vCPU, 20% baseline, 24 credits/hr, 576 cap, Unlimited mode by default).
api-2 is a warm standby — it has served no production traffic for at least 30 days (0.09 GB in over
7 days, vs api-3's 287 GB; a 4,700× packet gap). That does not make it disposable: it must be able to
absorb api-3's entire load on failover, which is why it goes to t4g.medium and not t4g.small.
Failover safety check — api-2 on t4g.medium carrying 100% of api-3's load (demand inflated 25% to
account for Graviton3 → Graviton2):
| Load level | On t4g.medium | Credits/hr | Result |
|---|---|---|---|
| Sustained (mean) | 13.7% CW | 16.4 spent vs 24 earned | Still accruing |
| p95 | 21.4% CW | 25.7 vs 24 | Net ‑1.7/hr — 340 h to drain a full cap |
| Peak 1-hr | 64.2% CW | 77.1 vs 24 | Net ‑53/hr — 10.8 h of cap; peaks last ~1 h |
The 24-hour average (13.7%) stays below the 20% baseline, so in Unlimited mode there is no surplus
charge and no throttling. Empirical backup: every t4g box in the fleet today sits pinned at the
576-credit cap with zero surplus — including jodgig.prod.cron, the busiest one.
Why not the alternatives: t4g.large (8 GB, $61.90) costs more than the c7g.large it would replace
and buys RAM that a 1 GB working set does not need. t4g.small (2 GB, $15.48) has identical CPU to
t4g.medium — same 2 vCPU, same 20% baseline, same 24 credits/hr — so it is purely a RAM decision, and 2 GB
against a 1 GB working set is too thin for a production API that is also the failover target.
The one prerequisite: leave NDS first
Account 140151801565 is still a member of NDS's AWS Organization (management account
767010522689, org o-0iovcybjee). NDS told us the migration would finish end of May. As of
2026-07-04 it has not. This is a reseller arbitrage, not a bill shock risk: you already pay
on-demand, so leaving is strictly cheaper.
NDS invoice 202605000003 (May 2026): total $2,895.42. EC2 "Compute Instance" is billed entirely at
On-Demand rates ($1,135.18 — e.g. $0.3332/hr for c7g.2xlarge), matching the AWS Pricing API to the
cent. Yet Cost Explorer shows that same compute as SavingsPlanCoveredUsage $1,097.71, canceled by
SavingsPlanNegation ‑$1,097.71 — a Savings Plan owned by NDS's payer account. AWS discounts the
compute for NDS; NDS invoices you full list.
Why this matters (and why there is no bill shock):
- Your 25 EC2 servers show
$0/hrin the AWS console because NDS's Savings Plan covers them there — but the NDS invoice charges you the full on-demand rate anyway. The discount is theirs. - So leaving NDS does not raise your compute bill — you are already paying on-demand. At worst you lose NDS's token 2% discount (~$58/mo). That is the entire downside.
- The upside: self-serve lets you buy your own Savings Plan and recapture the spread NDS keeps (~$180–240/mo), plus RDS Reserved Instances (which NDS is not buying for you either).
| Monthly | ||
|---|---|---|
| NDS invoice today | $2,895.42 | on-demand − 2% NDS discount |
| Self-serve, do nothing | ~$2,953.70 | +$58/mo (lose the 2% only) |
| Self-serve + your own SP | ~$2,712 | recapture the SP spread |
| Self-serve + SP + RDS RIs + rightsize | ~$1,800–2,100 | the full plan |
Action: ask NDS, in writing, to run RemoveAccountFromOrganization for account 140151801565, or
complete standalone sign-up so you can leave yourself. Full checklist in the
billing migration section below.
The correct order of work
STEP 0 Exit NDS → become your own payer (billing prerequisite) ⬜ BLOCKED ON NDS
STEP 1 Rightsize the 2 idle c7g.2xlarge servers ($365/mo, no commitment) 🟡 api-2 DONE, api-3 OPEN
STEP 2 Kill waste: idle EIPs, unattached disks, gp2 (~$50/mo, no commitment) 🟡 MOSTLY DONE (~$34/mo)
STEP 3 Buy RDS Reserved Instances on stable prod DBs (~$201/mo, buyable now) ⬜ OPEN — 5 DBs, not 6
STEP 4 Buy your own EC2 Compute Savings Plan (after Step 0 + Step 1) ⬜ OPEN
STEP 5 (Optional) Schedule QA off-hours (~$150/mo) ⬜ OPEN
Buying a 1–3 year commitment before rightsizing (Step 1) locks in the waste for the whole term. Always rightsize first, then reserve the smaller box.
Where you are: Steps 1–2 are $412/mo banked with no commitment (see
Progress). The single highest-value action left is
finishing Step 1 on $30/mo). Step 3 is buyable today and does not wait on NDS, because reservations travel with
the account.jodgig.prod.api-3 → t4g.medium (~$212/mo), with api-2 following it to the
same target (
Step 0 — Exit NDS (billing prerequisite)
There is no compute cost cliff — you already pay on-demand via NDS, so your bill does not jump when you leave (you only lose NDS's 2% discount, ~$58/mo). The checklist is just about a clean handover:
☐ Confirm YOU control the root email of account 140151801565 (not NDS)
☐ Add your own payment method to the account (Billing → Payment methods)
☐ Finish Step 1 (rightsize) so the SP you buy in Step 4 is sized to a lean fleet
☐ Soon after standalone: buy your own Compute Savings Plan (recaptures ~$180–240/mo NDS keeps)
☐ Buy RDS RIs on your own payment method
How you leave depends on how NDS created the account:
| How NDS set it up | Can you click "Leave organization"? | What to do |
|---|---|---|
| Invited your existing account | Yes, once standalone billing info is added | Add payment method + verify, then Organizations → Leave organization |
| Created the account for you | No (greyed out) until standalone sign-up is done | Have NDS run RemoveAccountFromOrganization, or finish AWS sign-up first |
Fastest clean path: make NDS remove you, in writing, since they already missed the deadline once.
Step 1 — Rightsize on real CPU history (the biggest free win)
This is $420/mo with no commitment and no architecture change. The sizing is driven by each instance's 30-day p95 CPU — not a rule of thumb. p95 is the right metric: the scary 84–99% max spikes are momentary, while the sustained load is near-zero almost everywhere.
CloudWatch CPUUtilization, 30 days (2026-06-04 → 07-04): p95 is below 2% on all but two of 25
instances. e.g. jodgig.prod.frontend (c7g.large) p95 0.27%; jodgig.prod.api-2 (c7g.2xlarge)
p95 0.19%. The exceptions: jodgig.prod.cron (p95 19%, real burst load — keep) and
JodProDockerDemoV2 (p95 95% — not idle, investigate).
Two rules make this safe and change-free:
- Graviton-only (
t4g). Every target is ARM64, same chip family as your currentc6g/c7g/t4g. No Dockerfile, base-image, or build change — just a smaller/cheaper instance of the same architecture. - RAM preserved. No memory metrics exist (the CloudWatch agent is not installed), so every target
keeps at least the current RAM. We move from compute-optimised (
c, 2 GB/vCPU) to burstable (t4g) because these workloads are idle-with-bursts — exactly what burstable is for.
| Instance | Now (RAM) | p95 CPU | → Target (RAM) | Now $/mo | After $/mo | Save |
|---|---|---|---|---|---|---|
jodgig.prod.api-2 | c7g.2xlarge (16 GB) | 0.19% | t4g.xlarge (16 GB) | 243.24 | 123.81 | 119.43 |
jodgig.prod.api-3 | c7g.2xlarge (16 GB) | 5.70% | t4g.xlarge (16 GB) | 243.24 | 123.81 | 119.43 |
jodgig.prod.frontend | c7g.large (4 GB) | 0.27% | t4g.medium (4 GB) | 60.81 | 30.95 | 29.86 |
jodgig.prod.reports | c7g.large (4 GB) | 0.62% | t4g.medium (4 GB) | 60.81 | 30.95 | 29.86 |
jodpro.prod.frontend | c6g.large (4 GB) | 0.66% | t4g.medium (4 GB) | 57.23 | 30.95 | 26.28 |
jodpro.prod.api | c6g.large (4 GB) | 0.63% | t4g.medium (4 GB) | 57.23 | 30.95 | 26.28 |
jod.prod.metabase † | t3a.large (8 GB, x86) | 3.11% | t4g.large (8 GB) | 68.91 | 61.90 | 7.01 |
jodpro.qa.api | t4g.medium (4 GB) | 0.56% | t4g.small (2 GB) | 30.95 | 15.48 | 15.48 |
jodgig.qa.api | t4g.medium (4 GB) | 0.79% | t4g.small (2 GB) | 30.95 | 15.48 | 15.48 |
jodpro.qa.frontend | t4g.medium (4 GB) | 0.27% | t4g.small (2 GB) | 30.95 | 15.48 | 15.48 |
jodgig.qa.frontend | t4g.medium (4 GB) | 0.23% | t4g.small (2 GB) | 30.95 | 15.48 | 15.48 |
| Total | $420.04 |
Notes that answer "is t4g.medium really right for QA?" — no, it was too big: your QA app servers run at
p95 < 1%, so t4g.small (2 GB) is plenty. The tiny/already-right boxes (t4g.small/micro prod,
jodgig.prod.cron) stay as-is.
- †
metabasemust stay on x86 — treat its $7.01 row as $0. The platform requires x86, so thet4g.large(ARM) target does not apply and the table row above is superseded. Under that constraintt3a.largeis already the cheapest 8 GB x86 instance inap-southeast-1— every alternative costs more (t3.large$77.09,m6a.large/m5a.large$78.84,t2.large$85.26,m5.large$87.60, all against $68.91). This box is already right-sized; there is nothing to do. The only lever left ist3a.medium(x86, 4 GB, $34.46 → saves $34.45/mo), which halves the RAM — check the Metabase JVM heap first, since Metabase is memory-hungry and this violates the RAM-preserved rule above. Not recommended without a measurement. - Phase 2 — resolved 2026-07-16, and it went further than this note expected. The plan was to install
the CloudWatch agent, measure memory for two weeks, then drop the
c7g.2xlargepair fromt4g.xlarge→t4g.largeif they used< 8 GB. A directhtopreading onapi-3under production load settled it without the agent: ~1 GB working set. That is not merely< 8 GB— it is< 2 GB, so the pair lands ont4g.medium(4 GB), two sizes below what this note anticipated. The 16 GB preserved in the table above was pure caution, and it costs ~$180/mo to keep. Memory is still worth instrumenting properly, but it is no longer blocking this decision. JodProDockerDemoV2is terminated (2026-07-16). This note previously warned against killing it because it ran at p95 95% CPU and looked like it was doing real work. It was retired deliberately along with the rest of thejodprofleet.
Step 2 — Kill waste (no commitment) — mostly done
Original estimate $50/mo; **$34/mo captured**, ~$32/mo still open (mostly the frontend-board pair).
| Item | Est. $/mo | Status |
|---|---|---|
| Release 4 idle Elastic IPs | 14.60 | ✅ Done — all four released |
Terminate stopped cron box JODv2-REPORT-PROD-CRON-env | 0.80 | ✅ Done — disk released too |
Kill demo box JodProDockerDemoV2 (t3.small) | 19.27 | ✅ Done — terminated |
| Convert gp2 → gp3 (EC2 volumes) | ~0.20 | ✅ Done — no gp2 EBS volumes remain |
Terminate frontend-board pair (prod + qa, t4g.small each) | 30.96 | ⬜ Planned |
Delete unattached volume vol-06c22cfc8ea0349cb | 0.77 | ⬜ Open |
| Convert gp2 → gp3 (RDS) | 0.00 | ❌ Void — no saving exists (see below) |
frontend-board — the remaining kill
jodgig.prod.frontend-board (i-0e11ca49e09dd716c) and jodgig.qa.frontend-board
(i-0282c085dc7b73f6f) are both t4g.small at $15.48/mo each = $30.96/mo. They were inside the
2026-07-04 count of 25 but were never listed separately, because at t4g.small they were already
right-sized — the plan had nothing to shrink. Terminating them is worth more than shrinking them ever was.
ec2 describe-instances 2026-07-16: both running, both t4g.small, both in the jodgig VPCs. Priced at
the exact t4g.small on-demand rate for ap-southeast-1 ($0.0212/hr × 730 = $15.48/mo).
Correction — RDS gp2 → gp3 saves nothing here
AWS Pricing API, ap-southeast-1, 2026-07-16: RDS GP2-Storage = $0.138/GB-mo and
GP3-Storage = $0.138/GB-mo — identical. EBS is the one that differs: gp2 $0.12 → gp3 $0.096/GB-mo
(‑20%).
The original ~$12/mo gp2→gp3 estimate applied the EBS discount to RDS storage. It does not transfer: in
this region RDS charges the same rate for both. The two remaining gp2 databases (jodgig-qa-sync 433 GB,
rds-jod-test-reports 20 GB) would save $0/mo from a conversion. gp3 may still be worth it for the
configurable IOPS baseline, but not as a cost action — do not book it as savings. The EC2 side of that
estimate was real and is already done.
Elastic IPs — all four now in use, none idle (done 2026-07-19)
The four idle EIPs are released, and the four that remain are all in use and correctly tagged. None should ever be released:
| EIP | Attached to | Role |
|---|---|---|
13.251.207.51 | jod.prod.haproxy (i-08d60a03c51ed35c2) | prod ingress — reserved IP behind Cloudflare |
3.1.7.254 | jod.qa.haproxy (i-0faaf01da0395180f) | qa ingress — new, replaces the auto-assigned IP |
52.221.32.130 | NAT gateway nat-03e1ba4b7af7c76f7 (prod-vpc-NAT-outbound) | Load-bearing — outbound internet for every private prod instance |
3.1.123.87 | NAT gateway nat-02f932aac7b5b27ec (qa-vpc-NAT-outbound) | Load-bearing — same, for QA |
Two fixes landed here:
jod.qa.haproxynow has a reserved Elastic IP (3.1.7.254). It previously ran on an auto-assigned address (54.169.122.201,IpOwner: amazon) that changes on every stop/start and would break the Cloudflare record. NowIpOwneris the JOD account (140151801565), so the IP survives resizes — QA is finally at parity with prod. This was cost-neutral: since 1 Feb 2024 AWS bills every in-use public IPv4 at ~$3.65/mo whether elastic or auto-assigned, so the unstable IP was already being paid for. A resilience fix worth $0, not a savings item.- The two NAT gateway EIPs were retagged from the ambiguous
prod-vpc/qa-vpctoprod-vpc-NAT-outbound/qa-vpc-NAT-outbound, so nobody mistakes a load-bearing gateway address for idle waste. (AWS refuses to release an EIP bound to a NAT gateway anyway, so this was a clarity fix, not an outage risk.)
Step 3 — RDS Reserved Instances (the main event)
RDS is 72% of your bill and is covered by nothing. Savings Plans do not apply to RDS — the mechanism here is Reserved Instances (RIs). Reserve only the stable production databases; QA/test databases should be scheduled off (Step 5), not reserved.
RDS reserved-offerings API, single-AZ (all our DBs are MultiAZ=false), 2026-07-04. On-demand at 730h.
Reserve the six stable production databases below; per-DB × per-option detail is in
jod-aws-savings-proposal.xlsx (tab "RDS Reserved").
Five prod DBs — the buy list as of 2026-07-16 (full per-DB matrix in the workbook):
| Database | Class | On-demand $/mo | 1yr No-Up $/mo | 3yr All-Up $/mo |
|---|---|---|---|---|
jodgig (whale) | db.m7g.2xlarge · mysql | 684.01 | 526.33 | 362.44 |
jodgig-replica-1 | db.t4g.medium · mysql | 74.46 | 58.40 | 42.28 |
metabase | db.t4g.medium · postgres | 74.46 | 58.40 | 42.28 |
jodapp | db.t4g.small · postgres | 37.23 | 29.20 | 21.14 |
jodgig-reports | db.t4g.micro · mysql | 18.25 | 14.60 | 10.56 |
| Total (prod) | $888.41 | $686.93 | $478.70 |
jodpro was in this list and is now goneThe 2026-07-04 version of this table had a sixth row — jodpro (db.t4g.micro · mysql, $18.25/mo). That
database has since been terminated (credited in the progress section).
Do not buy a reservation for it. The totals above are the live five-database buy list.
Every payment option — this is the table for the approval decision:
| Payment option | RDS $/mo | Save $/mo | Upfront cash |
|---|---|---|---|
| On-demand (today) | 906.66 | — | — |
| 1yr No Upfront | 701.53 | 205 | $0 |
| 1yr Partial Upfront | 680.02 | 227 | $4,078 |
| 1yr All Upfront | 661.59 | 245 | $7,939 |
| 3yr Partial Upfront | 505.90 | 401 | $9,093 |
| 3yr All Upfront | 489.26 | 417 | $17,613 |
jodpro — the decision does not changeThese rows were priced across all six databases on 2026-07-04. With jodpro terminated, each $/mo
figure drops by roughly $15–18, but the savings deltas barely move (1yr No Upfront: $205 → $201),
because jodpro was 2% of the RDS bill. The approval decision is unaffected, so the rows are left as
priced rather than re-derived. Use the five-database totals above for the actual purchase.
AWS offers no 3-year No-Upfront for RDS — 3-year requires Partial or All upfront. All 1-year No-Upfront RIs break even immediately (month 0, zero cash).
Recommended approach — two phases, low risk:
- Now (even a small step before self-serve is fine — RIs travel with the account): put all five surviving prod DBs on 1-year No-Upfront. Zero cash, breaks even immediately (month 0), saves ~$201/mo.
- After 2–3 stable months as self-serve: convert the small, definitely-permanent DBs
(
jodapp,jodgig-reports,metabase) to 3-year. Keep the whalejodgigon 1-year until you have tested whether it can drop tom7g.xlarge— it averages 20% CPU but spikes to 99%, so do not lock a 3-year reservation onto it yet.
RDS jodgig CPU: avg 20.3%, max 98.9% (30 days). Low average suggests headroom, but the 99% peaks are
real load — m7g.xlarge (half the size) may not survive peaks. Test before reserving 3 years.
How to buy one (whale example — get the offering ID, then purchase):
# 1. find the 1yr No-Upfront single-AZ offering id
aws rds describe-reserved-db-instances-offerings \
--db-instance-class db.m7g.2xlarge --product-description mysql \
--duration 31536000 \
--query "ReservedDBInstancesOfferings[?MultiAZ==\`false\` && OfferingType=='No Upfront'].ReservedDBInstancesOfferingId" \
--output text
# 2. purchase it
aws rds purchase-reserved-db-instances-offering \
--reserved-db-instances-offering-id <offering-id-from-step-1> \
--db-instance-count 1
Step 4 — EC2 Compute Savings Plan (after self-serve)
Once you are your own payer and have rightsized (Step 1), replace NDS's coverage with your own Compute Savings Plan. Use Compute SP (not EC2-Instance SP) — it is flexible across instance family, size, and region, which suits a fleet that still changes.
EC2 Compute SP rates are exact — from the Savings Plans offering-rates API (the same data as the
public compute-pricing page), t4g Linux
ap-southeast-1. The discount is uniform across t4g sizes: 27.7% (1yr no-up) → 55.8% (3yr all-up).
Applied to the right-sized production compute baseline of $557/mo (QA is handled by scheduling,
not an SP).
| Payment option | Discount | EC2 compute $/mo | Save $/mo | Upfront |
|---|---|---|---|---|
| On-demand (right-sized) | — | 557 | — | — |
| 1yr No Upfront | 27.7% | 403 | 154 | $0 |
| 1yr Partial Upfront | 31.1% | 384 | 173 | $2,303 |
| 1yr All Upfront | 32.5% | 376 | 181 | $4,513 |
| 3yr No Upfront | 51.3% | 271 | 286 | $0 |
| 3yr Partial Upfront | 55.0% | 251 | 306 | $4,513 |
| 3yr All Upfront | 55.8% | 246 | 311 | $8,865 |
Note the standout: 3-year No-Upfront gives 51% off for zero cash — unlike RDS, Compute SPs do offer 3-year No-Upfront. If you're confident the compute baseline is stable, it's the best cash-free deep cut.
Size the hourly commitment to your steady baseline only (roughly the always-on prod servers), not the peak. Anything above the commitment simply runs at on-demand — under-committing is cheap to fix, over- committing is locked for the term. Start conservative.
Step 5 — Schedule QA off-hours (optional, ~$150/mo)
QA does not need to run nights and weekends. QA EC2 ($193/mo) + QA RDS ($147/mo) ≈ $340/mo of
resources that are idle ~70% of the week.
Estimate only: running QA ~50h/week instead of 168h ≈ 70% off the QA compute + DB line, ~$150/mo. Needs automation (AWS Instance Scheduler, or an EventBridge + Lambda stop/start). RDS auto-restarts after 7 stopped days, so scheduling must restart weekly.
Do not buy RIs for QA databases — a reservation you turn off nightly is wasted money. Schedule instead.
Decision summary
| If you want… | Do this | Saves |
|---|---|---|
| ✅ Already banked (2026-07-04 → 07-16) | Right-sized api-2, retired jodpro + demo box, released idle EIPs | ~$412/mo |
| The safest next move, zero cash, this week | Finish Step 1 — the API pair to t4g.medium ($242), frontend, reports, QA pair, kill frontend-board | ~$365/mo more |
| Best commitment-free move that does not wait on NDS | Step 3: 1yr No-Upfront RIs on the 5 prod DBs | ~$201/mo more |
| Maximum savings with no upfront cash | Plan B: rightsize + 1yr No-Upfront (SP + RIs) | $779/mo |
| Deep cut, still no cash (if compute is stable) | rightsize + 3yr No-Up SP + 1yr No-Up RDS | ~$865/mo ($0 upfront) |
| Deepest savings, willing to pay upfront | rightsize + 3yr All-Upfront (SP + RIs) | $1,148/mo ($26.5k upfront) |
The last three rows are the original 2026-07-04 projections, kept as-issued so the plan can be judged against what it promised. They are measured from the $2,925 baseline, so the ~$412/mo already banked is part of those figures, not additional to them.
Recommended: do Steps 1–2 immediately (free, reversible). Finish the NDS exit (Step 0). Then take
Plan B (1-year, no upfront) — zero cash, no lock-in, and it captures 68% of the maximum monthly
saving. Paying $12.5k upfront for the 1-year all-upfront buys only ~$67/mo more (~6% return); not worth it.
The bigger lever is the term — 3-year nearly doubles the discount — so move stable databases + compute
to 3-year once standalone and confident. The full option-by-option comparison is in
jod-aws-savings-proposal.xlsx.
Appendix — how these numbers were produced
All figures come from live AWS reads on 2026-07-04 via a read-only IAM user (ali-claude): ec2 /
rds describe APIs (inventory), Cost Explorer get-cost-and-usage + get-reservation-purchase- recommendation (spend), the Pricing API (EC2 on-demand), the RDS reserved-offerings API (RI rates),
the Savings Plans offering-rates API (SP rates), and CloudWatch CPUUtilization (rightsizing). The
per-resource workbook is in the paired cost spreadsheet.
- Why on-demand list, not the $1,958 console figure: the console hides EC2 compute behind NDS's Savings Plan. After self-serve that discount is gone, so planning on-demand is the honest baseline.
- EC2 Savings Plan rates are estimates (~22% / ~33%), calibrated from two live API data points and clearly marked. Everything else (on-demand, RDS RI) is exact from AWS APIs.
- Tax (~$162/mo) is excluded from the optimisation math; it scales with the bill, so cutting spend cuts tax proportionally.