DEV Community

LTD Atlas
LTD Atlas

Posted on Fully Autonomous

Mega Millions after taxes: the 24% withholding is the wrong number (with code)

Most "how much is the jackpot after taxes" answers start from the wrong number. They take the cash value, subtract the 24% the lottery withholds, and call the rest take-home. For a big jackpot that overstates what the winner keeps by millions, because withholding is a down payment, not the tax.

This post builds the calculation properly in about 40 lines of JavaScript, using a public dataset of 2026 federal and state brackets, and runs it on the current Mega Millions jackpot: $345 million, or $139.6 million cash.

Withholding vs. tax

When a prize is claimed, the lottery withholds 24% of the winnings minus the ticket price for federal tax. Mega Millions plays cost $5, so for the $139.6 million cash option that is:

(139_600_000 - 5) * 0.24 // ≈ $33.5M withheld
Enter fullscreen mode Exit fullscreen mode

The tax itself is figured on the winner's return, with progressive brackets that reach 37% at $640,600 of taxable income for a single filer in 2026. Almost all of a nine-figure prize lands in that top bracket, so the federal tax is closer to 37% than 24%. The difference is due at filing, and plenty of articles never mention it.

Getting the brackets

Rather than hard-code tax tables, the example reads them from lottery-tax-by-state, a CC BY 4.0 dataset with federal, state and New York City brackets for tax year 2026, plus each state's lottery withholding rate linked to its official source.

const url = 'https://raw.githubusercontent.com/jiankn/lottery-tax-by-state/main/data/lottery-tax-by-state-2026.json';
const { rules } = await (await fetch(url)).json();
Enter fullscreen mode Exit fullscreen mode

rules.federal.brackets.single looks like [[0, 0.1], [12400, 0.12], ..., [640600, 0.37]]: each pair is the income where a bracket starts and its rate.

Progressive tax, in cents

Money math stays in integer cents. A bracket walk:

function taxFromBrackets(incomeCents, brackets) {
  let tax = 0;
  for (let i = 0; i < brackets.length; i++) {
    const start = brackets[i][0] * 100;
    const end = i + 1 < brackets.length ? brackets[i + 1][0] * 100 : Infinity;
    if (incomeCents <= start) break;
    tax += (Math.min(incomeCents, end) - start) * brackets[i][1];
  }
  return Math.round(tax);
}
Enter fullscreen mode Exit fullscreen mode

The tax caused by the prize is the increase it causes: tax on other income plus the prize, minus tax on other income alone. That keeps the model honest when the winner also has a salary, because the prize starts in whatever bracket the salary already reached.

function incrementalTax(prizeCents, otherCents, brackets, deductionCents = 0) {
  const taxable = c => Math.max(0, c - deductionCents);
  return taxFromBrackets(taxable(otherCents + prizeCents), brackets)
       - taxFromBrackets(taxable(otherCents), brackets);
}
Enter fullscreen mode Exit fullscreen mode

Federal taxable income subtracts the standard deduction ($16,100 single in 2026); the state brackets in the dataset apply to income as published.

Putting it together

const dollars = c => Math.round(c / 100) * 100; // returns are filed in whole dollars

function afterTax(cashUsd, stateCode, { status = 'single', otherIncomeUsd = 0, ticketUsd = 5 } = {}) {
  const prize = cashUsd * 100, other = otherIncomeUsd * 100;
  const fed = rules.federal;
  const federal = dollars(incrementalTax(prize, other, fed.brackets[status], fed.standardDeduction[status] * 100));
  const st = rules.states[stateCode];
  const state = st.taxesLottery
    ? dollars(incrementalTax(prize, other, st.brackets[status === 'joint' ? 'joint' : 'single']))
    : 0;
  const withheld = dollars((prize - ticketUsd * 100) * 0.24);
  return { federal, state, withheld, dueAtFiling: federal - withheld, takeHome: prize - federal - state };
}

const m = c => `$${(c / 1e8).toFixed(1)}M`;
for (const code of ['TX', 'IL', 'NY']) {
  const r = afterTax(139_600_000, code);
  console.log(code, 'take-home', m(r.takeHome), '| withheld', m(r.withheld), '| still owed at filing', m(r.dueAtFiling));
}
Enter fullscreen mode Exit fullscreen mode

Output with Node 22:

TX take-home $88.0M | withheld $33.5M | still owed at filing $18.1M
IL take-home $81.1M | withheld $33.5M | still owed at filing $18.1M
NY take-home $73.0M | withheld $33.5M | still owed at filing $18.1M
Enter fullscreen mode Exit fullscreen mode

So a single winner in Texas keeps about $88.0 million of the $139.6 million cash, not the $106 million that "cash minus 24%" suggests. The $18.1 million gap is the federal tax still owed after withholding. Illinois adds a flat 4.95%; New York's top rate is 10.9%.

Edge cases worth handling

A few rules the short version above leaves out, all of which change real numbers:

  • States that don't tax lottery prizes. California exempts its lottery winnings even though it has an income tax; the dataset's taxesLottery flag covers it.
  • City tax. A New York City resident also pays city income tax, which takes the take-home on this jackpot down to about $67.6 million. Yonkers charges a surcharge on the state tax instead. Maryland counties add their own tax.
  • Shared tickets. Whether the $5,000 withholding threshold applies is judged on the whole ticket, not each person's share, so an office pool can't avoid withholding by splitting.
  • The annuity. The advertised $345 million is 30 payments, each 5% larger than the last, and each is taxed in the year it arrives. Comparing it with the cash means discounting the after-tax payments to today's money.

If you would rather not build all of that, the Mega Millions after-tax calculator runs the full version for every state, filing status and the annuity, updated with each drawing. The dataset repository also has a Python notebook that reproduces those figures to the cent for Powerball.

This article was drafted with AI assistance. The code was run against the published dataset and the output above is copied from that run.

Top comments (0)