Calculate barbell plate loading per side
For 100 on a 20 bar, load one 25 and one 15 on each side: 80 in plates, 40 per side, with the fewest plates possible. It finds exact loads even where grabbing the biggest plate first fails. Free in your browser.
- Free
- Runs in your browser
- No sign-up
- Your data stays on your device
Run — free
Worked example
- Target weight
- 100
- Bar weight
- 20
- Weight per side
- 40
- Achieved total weight
- 100
- Difference from target
- 0
Turn a target barbell weight into a clear plate-loading plan for each side. Enter the total weight you want, the empty bar weight, and the plate denominations available in your gym. The calculator finds an exact combination when one exists, even for denomination sets where a simple largest-first method would fail. If exact loading is impossible, it reports an error unless you explicitly request the nearest achievable result. Every response includes the achieved total and its difference from the target.
Enter the total, bar, and available plate sizes
Start with the target total weight, which means everything you intend to lift: the bar plus matching plates on both ends. Then enter the weight of the empty bar and list each plate denomination available to you. The numbers can represent kilograms or pounds as long as every field uses the same unit; the calculator does not convert between measurement systems.
List a denomination once, because the algorithm treats each size as reusable and determines how many copies belong on each side. For example, a target of 100 with a 20-unit bar leaves 80 units for plates, or 40 per side. With 25, 20, 15, 10, 5, 2.5, and 1.25 available, one 25 and one 15 on each side reaches the target exactly.
The plate list in the result always describes one side, so repeat the identical arrangement on the other side and secure both ends before lifting.
Find exact combinations instead of relying on greedy loading
Plate loading looks simple, but always choosing the largest plate that fits can produce the wrong answer for unusual inventories. A greedy pass might get stuck even though a different combination reaches the target. This calculator searches attainable per-side weights with a bounded dynamic-programming table, so it finds a valid exact combination whenever one exists within the declared limits.
Among exact combinations, it prefers fewer plates, which generally produces a quicker and less cluttered setup. The response shows each denomination and quantity per side, the combined plate weight for one side, the achieved total weight, the signed difference from the requested target, and whether the result is exact. Decimal weights are converted to scaled integers during the search, avoiding the familiar floating-point remainder problems that can make values such as 1.25 appear slightly above or below their mathematical value.
Duplicate denominations are harmless and are consolidated before calculation.
Control what happens when the target is unavailable
Some targets cannot be made from a particular bar and plate set. Because plates must be balanced, every plate placed on one side requires an equal plate on the other, so the total changes in twice-denomination increments. By default, an unreachable request returns an invalid-input error rather than silently prescribing a different workout weight.
This is useful for training software, where substituting an approximate load without permission could alter the planned session. The solver then selects the attainable total with the smallest absolute difference from the target; if equally close lighter and heavier totals exist, it chooses the lighter one deterministically. The empty bar itself is considered a possible closest result.
Always verify the bar markings, plate labels, collars, and final total in person, since this arithmetic tool cannot inspect equipment condition or confirm what was physically loaded.
What you can do with it
Prepare a strength workout
Convert every programmed working weight into a per-side loading instruction before the session begins.
Use a limited home-gym inventory
Supply only the denominations you own and identify targets that your current plate set cannot build exactly.
Add loading cues to a coaching app
Generate deterministic plate counts, achieved totals, and target differences for athlete-facing workout screens.
FAQ
Are the listed plates for one side or both sides?
Load the same denominations and counts on the other end.
Can I use pounds instead of kilograms?
Yes. Use the same unit for the target, bar, and every plate denomination; output values remain in that unit.
How are equally close alternatives resolved?
The lighter achievable total wins a distance tie, making the result stable and conservative.
What happens if my target can't be loaded exactly?
By default you are told that the weight cannot be reached with your bar and plates. If an approximation is fine, ask for the nearest loadable total; the result then shows how much lighter or heavier it is than your target.
Why not just put on the biggest plate that fits?
Because with some plate sets that shortcut gets stuck even though another combination reaches the target. The calculator checks the reachable weights and, among exact options, picks the one with the fewest plates.
Related tools
For developers — API access
Everything on this page is available programmatically. This section is for teams who want to wire it into their own systems; everyone else can just use the tool above.
API endpoint
Prefer to automate it? One authenticated POST creates the task; the result comes back by webhook or a signed link. The same capability also runs here on the web, by email and from Telegram — and soon from our app too.
Call it from your stack
curl -X POST https://api.kit.forhosting.com/fitness2/plate-math-calculate \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"target_weight":100,"bar_weight":20,"plates":[25,20,15,10,5,2.5,1.25]}'const res = await fetch("https://api.kit.forhosting.com/fitness2/plate-math-calculate", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"target_weight": 100,
"bar_weight": 20,
"plates": [
25,
20,
15,
10,
5,
2.5,
1.25
]
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/fitness2/plate-math-calculate",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"target_weight": 100,
"bar_weight": 20,
"plates": [
25,
20,
15,
10,
5,
2.5,
1.25
]
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/fitness2/plate-math-calculate", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"target_weight":100,"bar_weight":20,"plates":[25,20,15,10,5,2.5,1.25]}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"target_weight":100,"bar_weight":20,"plates":[25,20,15,10,5,2.5,1.25]}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/fitness2/plate-math-calculate", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Example request
{
"target_weight": 100,
"bar_weight": 20,
"plates": [
25,
20,
15,
10,
5,
2.5,
1.25
]
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "fitness2.plate_math_calculate",
"status": "queued",
"_links": {
"result": "/tasks/tsk_…/result"
}
}The API is asynchronous: the call returns a task_id immediately and the result arrives by webhook. Polling is capped at 1 req/s per task.
Pricing
Published price — no tokens, no invented credits. A failed task is never charged.
Limits
max_target_weight | 2000 |
max_plate_denominations | 50 |
max_decimal_places | 3 |
Errors
| HTTP | Code | Meaning |
|---|---|---|
401 | unauthorized | Missing or invalid API key. |
402 | insufficient_balance | Your balance doesn't cover the task price. |
404 | unknown_type | That task type doesn't exist. |
429 | rate_limited | Too many requests. Use the webhook instead of polling. |
Technical notes
Control what happens when the target is unavailable
Set closest_match to true when an approximation is acceptable. Check difference_from_target to see the signed adjustment: a negative value is lighter and a positive value is heavier.
Technical questions
What does the API request cost?
Each successful API request starts at $0.002. The calculation is deterministic and uses no external service.
What happens when the exact target is impossible?
The default behavior is an invalid_input error. Set closest_match to true to receive the nearest achievable total.