How to variable font vs multiple weights — quantify it per weight count
- Step 1List the static weights you're weighing — Write down each weight you'd otherwise ship (Light, Regular, Medium, Bold...). The count is what you'll look up.
- Step 2Upload the single variable font — Drop the variable master (`.ttf`/`.otf`/`.woff`/`.woff2`). The tool only takes one file; you don't upload the statics.
- Step 3Confirm it's variable — Check `axes` > 0 in the output. Zero axes means no `fvar` table — you uploaded a static file and the comparison won't mean anything.
- Step 4Scan the projections curve — Walk `projections` from 1 to 9 weights, watching `delta_bytes` go from negative (variable wastes bytes) through zero-ish to strongly positive (static is far heavier).
- Step 5Read your current count — Find the row matching today's weight list; `variable_wins` is your answer right now.
- Step 6Plan for change — Look one or two rows up to see whether adding weights would change the answer (it only strengthens variable). Then route: keep variable, or freeze with the [Variable Font Freezer](/font-tools/variable-font-freezer) and subset with the [Font Subsetter](/font-tools/font-subsetter).
Per-count projection shape
One object per weight count from 1 to 9. variable_bytes is constant; the static side scales linearly.
| Field | Meaning |
|---|---|
static_weight_count | The number of static weights modelled (1-9) |
estimated_static_total_bytes | per_weight_estimate * static_weight_count |
variable_bytes | Constant = uploaded variable file size |
variable_wins | true when static total > variable bytes |
delta_bytes | static_total - variable_bytes (signed) |
Curve for a 200 KB variable font
Per-weight estimate = 80 KB. Sign of delta_bytes is the whole story.
| Weights | Static total | delta_bytes | variable_wins |
|---|---|---|---|
| 1 | 80 KB | -120 KB | false |
| 2 | 160 KB | -40 KB | false |
| 3 | 240 KB | +40 KB | true |
| 4 | 320 KB | +120 KB | true |
| 6 | 480 KB | +280 KB | true |
| 9 | 720 KB | +520 KB | true |
Cookbook
The trade-off curve for representative fonts. Substitute your variable file's size; the shape (crossing at 3) is constant.
Today 2 weights, considering a 3rd
ExampleA site on Regular + Bold thinking about adding Semibold. The decision flips at the third weight.
Upload: UI-Variable.woff2 (variable_file_bytes 200000) per_weight_estimate: 80000 2 weights: delta_bytes -40000 variable_wins false -> statics win 3 weights: delta_bytes +40000 variable_wins true -> variable wins Adding Semibold tips the scales to the variable file.
Five weights — variable, no contest
ExampleA type-rich editorial site.
5 weights: estimated_static_total_bytes: 400000 variable_bytes: 200000 variable_wins: true delta_bytes: 200000 (statics would double the bytes)
One weight — keep it static
ExampleA utility app that only renders one weight.
1 weight: estimated_static_total_bytes: 80000 variable_bytes: 200000 variable_wins: false delta_bytes: -120000 # Freeze the single instance instead of shipping the variable file.
Static file slipped in
Exampleaxes:0 means there are no weights to vary — comparison void.
variable_file_bytes: 70000 axes: 0 glyph_count: 690 # This is a static weight, not a variable family. Upload the master.
Diffing the verdict when the weight list changes
ExampleRe-run after a design change and diff the JSON in the PR.
- 2 weights: variable_wins false + 4 weights: variable_wins true # The added weights moved the right answer to 'ship variable'.
Edge cases and what actually happens
Every row below was probed against the live API. Some documented requirements (alphabetical axis order, numerical tuple order) are not actually enforced in practice — useful to know if you've been blaming the wrong thing for a 400.
No file uploaded
Error: Upload a variable font.A file is mandatory; the handler throws without one. There's no built-in sample.
You only weigh one weight
Static winsAt 1 weight the static estimate (40% of variable) is smaller than the whole variable file, so variable_wins is false. That's correct — a single weight rarely justifies a variable file.
Static side is estimated, not measured
Heuristic onlyEach static weight is 0.4 * variable_size. The tool never builds or weighs actual static instances, so deltas near the 3-weight crossing are the least reliable.
Crossing is always at 3
By constructionBecause the per-weight figure is 40% of variable, the curve crosses zero between 2 and 3 weights for every font; breakeven_static_count is always 3.
Uploaded a static font
axes: 0No fvar table -> axes 0 -> the comparison is meaningless. Upload the variable master with axes.
Uncompressed input
Skews variable sidevariable_bytes is the uploaded size. An uncompressed TTF makes variable look heavier than the WOFF2 you'd serve; upload the served file for a fair curve.
Over free 5 MB / 1,000 glyphs
Rejected (tier limit)Free tier limits: 5 MB and 1,000 glyphs. Larger families need Pro.
Two fonts at once
Not supportedSingle-file tool. To compare two distinct fonts, analyse each on its own.
Options passed
IgnoredNo options influence the result; you always receive the full 1-9 curve.
Bad/unknown format
Error: Unsupported font formatOnly TTF/OTF/WOFF/WOFF2 pass the magic-byte check.
Frequently asked questions
One variable file or several static weights — which is smaller?
Look up your weight count in projections. variable_wins: true means the single variable file is projected lighter than that many static weights; false means the statics win.
At how many weights does variable start to win?
Three. The static stack reaches 120% of the variable size at 3 weights (3 x 40%), so the variable file becomes the lighter choice from there.
Do I upload the static fonts too?
No. You upload only the one variable file; the static side is estimated from its size at 40% per weight.
Is the static estimate accurate?
It's a fixed heuristic, not a measurement. For real static sizes, freeze instances with the Variable Font Freezer and weigh them.
What does delta_bytes tell me?
The signed byte difference: positive means the static stack would cost that much more (variable wins); negative means variable wastes that many bytes (static wins).
Why give me 1 to 9 weights when I only use 3?
So you can see how the answer moves if the design adds or drops weights. Adding weights only strengthens the case for variable.
What if axes is 0?
You uploaded a static font (no fvar). The comparison is void; upload the variable master.
Does input format change the result?
Yes for the variable side — variable_bytes equals the uploaded file size. Upload the served WOFF2 for a realistic curve.
How do I count my weights?
Count distinct font-weight values in your CSS — e.g. 300/400/700 is three.
Variable wins — what next?
Keep it and generate the CSS with the Google Fonts CSS Generator; ensure it loads efficiently via Preload Tag Builder.
Static wins — what next?
Freeze the needed instances with the Variable Font Freezer, then subset each with the Font Subsetter.
Any limits I should know?
Free tier: 5 MB, 1,000 glyphs, one file. Pro: 50 MB, 65,536 glyphs.
Privacy first
Every JAD Font tool runs entirely in your browser using opentype.js and the wawoff2 WASM Brotli encoder. Your fonts never leave your device — verified by zero outbound network requests during processing.