Learn / Explainer

Where should the next dollar of inventory go? Allocating a budget across SKUs

When the budget cannot cover every SKU's optimal buy, the usual answers are one service level for all or an equal cut. Both allocate by rule. Ranking every unit by its expected return per dollar allocates by value, and the difference grows as money gets tight.

By Adam DeJans Jr. · October 23, 2026 · 18 min read

The order-economics guide sets each SKU’s buy on its own: price the two ways to be wrong, take the critical-ratio quantile of the forecast. In practice, the sum of those buys rarely matches the money available. There is an open-to-buy budget, a cash ceiling, a warehouse that holds so much, a container that carries so much. So the real question is not only how much of each SKU, but which SKUs get the money first.

Most organizations answer it with a rule:

  1. One service level for everyone. Lower the target until the plan fits: “this season we buy to 90% instead of 95%.”
  2. An equal cut. Compute every buy, then trim each by the same percentage. Both decide by rule how scarce money is shared. None of them asks what each dollar would earn. This piece shows how to ask that question directly, what the answer looks like, and when it matters.

Every unit has its own expected return

Think of a buy not as a quantity per SKU but as a long list of individual units: the 1st trail runner, the 2nd, and so on up to the 136th; the 1st pair of socks up to the 786th. Each unit has an expected profit of its own. The kk-th unit sells if demand reaches kk, earning the price; otherwise it is cleared at the salvage value. With unit cost cc, price pp and clearance value vv,

Δk  =  (p−v) P(D≥k)  −  (c−v),rk  =  Δkc.\Delta_k \;=\; (p - v)\,P(D \ge k) \;-\; (c - v), \qquad r_k \;=\; \frac{\Delta_k}{c}.

Δk\Delta_k is the unit’s expected profit and rkr_k its expected return per dollar spent. The first unit of an item almost always sells, so it returns the full markup, (p−c)/c(p - c)/c. Each additional unit is a little less likely to sell, so returns fall steadily until they reach zero at the critical-ratio quantile, which is exactly where the unconstrained newsvendor stops.

Rank every unit, then buy from the top

If the returns of all units of all SKUs are put in one list and sorted, the best use of a budget is to buy from the top of the list until the money runs out. Because each SKU’s returns only fall as you buy more of it, nothing further down the list can beat anything above it. This is the whole method. It needs nothing beyond the forecast and the unit economics you already have.

The exhibit applies it to a seasonal buy for an outdoor store with eight SKUs. Drag the budget down from the unconstrained optimum and watch where the money goes.

Exhibit 1 · Interactive

Rank every unit by what it earns per dollar, then buy from the top until the money runs out

Expected profit, ranked list
One service level for all
Cut every buy equally
Value of the next $1,000
expected profit it would add

Expected return per dollar of each successive unit, best first. The shaded area is the expected profit the budget buys.

What each SKU gets: units bought out of its unconstrained optimum, and the chance of not selling out

Ranked list One service level for all

A seasonal buy for an outdoor store; lognormal demand per SKU. Trail runners: cost $60, price $130, clearance $30, forecast 120 ± 48; Rain shell: cost $45, price $110, clearance $15, forecast 80 ± 48; Wool socks: cost $4, price $16, clearance $2, forecast 600 ± 180; Headlamp: cost $18, price $40, clearance $10, forecast 200 ± 100; Down parka: cost $140, price $260, clearance $50, forecast 40 ± 32; Water bottle: cost $6, price $15, clearance $3, forecast 400 ± 140; Trekking poles: cost $35, price $70, clearance $20, forecast 70 ± 49; Novelty mug: cost $8, price $14, clearance $1, forecast 150 ± 135. The budget slider runs to the spend of the unconstrained optimum, where every SKU buys its own critical-ratio quantity.

What the list does that rules cannot

At half of the unconstrained budget, the ranked list allocates as follows. The “one service level” rule, for comparison, has to drop to a 17% in-stock probability for every SKU to fit the same budget.

SKUMarkupUnconstrained buyRanked list buysRanked list in-stockOne service level buysEqual cut buys
Wool socks300%78662862%434393
Water bottle150%47532433%273237
Rain shell144%895028%4044
Headlamp122%24012522%114120
Trail runners117%1368019%7768
Trekking poles100%802611%3140
Down parka86%3561%1517
Novelty mug75%10400%5352

Four things stand out.

  1. Some SKUs get nothing. The last unit the budget buys earns 84 cents per dollar. The first novelty mug earns 75 cents, less than that, so no mug makes the cut, even though the mug sells 150 a season. The rule is general: when the last dollar earns a return λ\lambda, every SKU whose markup is below λ\lambda gets nothing, whatever its volume. The down parka, at an 86% markup, barely clears the bar and gets 6 units.
  2. Service levels are an output, and they differ widely. In-stock probabilities run from 62% for socks to zero for mugs. The “one service level” rule forces them all to 17%, which overbuys the parka and the mug and underbuys the socks and bottles that earn the most per dollar.
  3. Size is not value. The parka has the highest price and the second-highest revenue in the assortment, and it is nearly cut out. A unit’s claim on the budget comes from what it earns per dollar, not from how big or how visible the item is. This is precisely where ABC classification goes wrong. Ranking by revenue would make the parka an A item and protect it first, sending scarce budget to the units that earn the least per dollar. ABC sorts items by size and then pretends the sort is an economic decision; it is not, and no choice of class boundaries fixes that.
  4. The budget has a price. The return on the last dollar, λ\lambda, is what one more dollar of budget would earn. At half budget, another $1,000 adds about $821 of expected profit. That is the number to bring to a budget discussion: if money costs less than that, the budget is too small.

The budget acts as a markup on every unit’s cost

The same result can be written in a form that connects back to the critical ratio. Spending the budget optimally is equivalent to solving each SKU on its own, but as if every unit cost c(1+λ)c(1 + \lambda) instead of cc:

F(Qi)  =  pi−ci (1+λ)pi−vi.F(Q_i) \;=\; \frac{p_i - c_i\,(1 + \lambda)}{p_i - v_i}.

This is the newsvendor critical ratio with an inflated cost, where λ\lambda is the Lagrange multiplier of the budget constraint. A tight budget raises the effective cost of every unit by the same percentage, which hurts low-markup items most and drives them to zero first. In the example, every SKU’s in-stock probability at half budget matches this formula to within two percentage points.

How much does it matter?

Less than you might think when money is loose, and a great deal when it is tight.

Exhibit 2

Rules of thumb are nearly harmless when money is loose and expensive when it is tight

10% 20% 30% 40% 50% 60% 70% 80% 90% 100% 10%25%50%75%100% Budget, as a share of the unconstrained buy expected profit, share of unconstrained +13% to +24% Cut every buy equallyRanked listOne service level
The same eight-SKU assortment as Exhibit 1. One service level: every SKU buys the same percentile of its demand, set as high as the budget allows. Equal cut: every SKU's unconstrained buy reduced by the same percentage. At the full budget the equal cut is optimal by construction; one service level is not.
BudgetRanked listOne service levelEqual cutRanked list advantage
100% ($31,011)$27,681$27,343$27,681+1.2% over one service level
75% ($23,258)$26,243$25,792$25,900+1.3% to +1.8%
50% ($15,506)$21,372$20,414$19,883+4.7% to +7.5%
30% ($9,303)$15,153$13,374$12,262+13.3% to +23.6%

Two conclusions follow. First, when the budget nearly covers the unconstrained buy, the rules of thumb cost about one to two percent, and the real gain comes from getting each SKU’s economics right in the first place. Even at full budget, one service level for all loses money, because it ignores that the optimal service level differs by SKU. Second, the tighter the budget, the more the allocation matters. At 30% of the unconstrained buy, the ranked list earns 13% to 24% more expected profit than the rules, from the same money and the same forecast. Tight budgets are exactly when organizations reach for blunt rules, and exactly when blunt rules cost the most.

Check it in a simulator

Everything above is computed from expected values. A season is not an expected value: demand comes in once, high for some SKUs and low for others, and the buy either fits it or does not. So the claims deserve a test that does not rely on the same formulas. A simulator provides it. Draw thousands of demand scenarios from the same forecasts, play the season out under each policy, and record what each one would actually have earned. Every policy faces exactly the same scenarios, so any difference comes from the quantities alone.

Exhibit 3 · Interactive

Play the season out 2,000 times: the ranked list wins most seasons and earns its edge in the good ones

Average season
Ranked list wins
of seasons, same demand
Bad season (10th pct.)
Good season (90th pct.)
Ranked list One service level

Each season draws every SKU's demand from its lognormal forecast (the same eight SKUs as Exhibit 1) and computes realized profit: sales at full price, leftovers cleared at the clearance value, less the cost of the buy. Both policies face the same 2,000 demand scenarios. Dashed lines mark each policy's average season.

In a run of 5,000 simulated seasons:

BudgetAverage profit: ranked list / one service level / equal cutSeasons the ranked list wins, against each ruleBad season (10th percentile): ranked list / one service level / equal cut
75%$26,232 / $25,765 / $25,88962% / 61%$21,938 / $21,866 / $21,991
50%$21,384 / $20,419 / $19,89973% / 81%$18,915 / $18,948 / $18,427
30%$15,156 / $13,372 / $12,26189% / 98%$13,312 / $13,302 / $12,036

Three things come out of it.

  1. The averages match the formulas to within sampling error. The expected-profit figures in the exhibits above are not artifacts of the approximation; they are what the season delivers on average.
  2. The ranked list wins most seasons, not all of them. It maximizes expected profit, which is a statement about the average. In roughly a third of seasons at a 75% budget, demand happens to favor what the rules bought. The tighter the budget, the more consistently the ranked list comes out ahead.
  3. It concentrates the budget, so outcomes spread more. The rules spread a small budget thinly across everything, which makes every unit very likely to sell and every season look alike. At half budget, one service level sells out of every SKU in nearly a quarter of seasons, so a strong season cannot earn it anything more. The ranked list puts the money where the return is highest, so good seasons are much better and bad seasons are about as bad as under the rules: the 10th-percentile seasons are within a few dollars of each other at every budget. The very worst seasons can be somewhat worse.

That third point is where a simulator earns its keep. If the business genuinely cares about bad seasons beyond their effect on the average, for example because a weak season breaches a covenant, that is a cost, and it can be priced: a penalty on profit below a threshold, or on cash tied up at season end. The simulator then scores each policy on that richer economic objective, scenario by scenario. What it should not do is replace the economics with a gut preference for “safer” allocations that nobody has priced.

The same tool covers what the closed-form math cannot: case packs and minimum orders, substitution between SKUs when one sells out, a shared truck, a markdown schedule. Write the rules of the season, feed it forecast scenarios, and let it score candidate decisions. The formulas find good candidates quickly; the simulator is how you check them against the world they will meet.

Beyond a cash budget

The same idea extends with small changes.

  1. Other scarce resources. If the binding limit is shelf space, warehouse volume or container capacity rather than cash, rank units by expected profit per unit of that resource: per cubic meter, per pallet position, per kilogram.
  2. Several limits at once. With a cash budget and a space limit together, one ranking no longer suffices. Each limit gets its own price, and the problem becomes a small linear or mixed-integer program. The prices still have the same meaning: what one more unit of each resource is worth.
  3. Lots and minimum orders. If a SKU can only be bought in cases of 12 or in a minimum order of 200, rank lots instead of units. The list is then a heuristic rather than exactly optimal, because lots are lumpy, which makes it a knapsack problem. In practice the greedy list is usually very close.
  4. Repeated replenishment. For stock that carries over, replace the clearance loss with the holding and ageing cost over the protection interval from How long does inventory need to last?. The ranking logic is the same: the next unit of each SKU earns its margin times the chance it is needed, minus the cost of carrying it if it is not.

In Python

Working from forecast samples keeps it general: any probabilistic forecast that produces demand scenarios can drive the list.

import numpy as np

rng = np.random.default_rng(0)

# name: (unit cost, price, clearance value, forecast mean, coefficient of variation)
skus = {
    "Trail runners":  (60, 130, 30, 120, 0.40),
    "Rain shell":     (45, 110, 15,  80, 0.60),
    "Wool socks":     ( 4,  16,  2, 600, 0.30),
    "Headlamp":       (18,  40, 10, 200, 0.50),
    "Down parka":     (140, 260, 50, 40, 0.80),
    "Water bottle":   ( 6,  15,  3, 400, 0.35),
    "Trekking poles": (35,  70, 20,  70, 0.70),
    "Novelty mug":    ( 8,  14,  1, 150, 0.90),
}

def forecast_samples(mean, cv, n=50_000):
    """Stand-in for a probabilistic forecast: demand scenarios for the season."""
    s2 = np.log(1 + cv**2)
    return rng.lognormal(np.log(mean) - s2 / 2, np.sqrt(s2), n)

# Every unit worth buying, with its expected profit and return per dollar.
units = []
for name, (c, p, v, mean, cv) in skus.items():
    d = np.sort(forecast_samples(mean, cv))
    k = np.arange(1, int(d[-1]) + 1)
    p_sold = 1 - np.searchsorted(d, k - 0.5) / len(d)   # chance the k-th unit sells
    value = (p - v) * p_sold - (c - v)                  # expected profit of the k-th unit
    for kk, val in zip(k, value):
        if val <= 0:
            break
        units.append((val / c, int(kk), name, val, c))

units.sort(key=lambda u: (-u[0], u[1]))                 # best return first

def allocate(budget):
    qty, spend, profit, last = {n: 0 for n in skus}, 0.0, 0.0, None
    for ret, k, name, val, c in units:
        if k == qty[name] + 1 and spend + c <= budget:
            qty[name], spend, profit, last = k, spend + c, profit + val, ret
    return qty, spend, profit, last

qty, spend, profit, last = allocate(15_506)
print(qty)
print(f"spend ${spend:,.0f}, expected profit ${profit:,.0f}, last dollar earns {last:.0%}")
# {'Trail runners': 80, 'Rain shell': 51, 'Wool socks': 629, 'Headlamp': 127,
#  'Down parka': 5, 'Water bottle': 327, 'Trekking poles': 27, 'Novelty mug': 0}
# spend $15,504, expected profit $21,369, last dollar earns 83%

The sample-based version reproduces the exact calculation used in the exhibits to within a few dollars. Sorting tens of thousands of candidate units is instant; for very large catalogs, a priority queue that only expands each SKU’s next unit does the same work without materializing the full list.

Common mistakes

  • Cutting every SKU by the same percentage. It keeps low-return units and drops high-return ones in equal measure.
  • Lowering one service level until the plan fits. It ignores that each SKU’s right service level was different to begin with, and the gap widens as the budget shrinks.
  • Ranking by revenue or volume, including ABC classes. What matters is expected profit per dollar of the scarce resource. High-revenue, low-markup items are often the first that should lose budget, which is the opposite of what an ABC policy does.
  • Treating zero as a failure. A SKU that gets nothing under a tight budget is not being neglected; its first unit earns less than the last unit of something else.
  • Judging a policy by one season. At half budget, the ranked list loses about one season in four to one service level and still earns more over time. Score policies across many simulated seasons, not on last year’s outcome.
  • Arguing about the budget without its price. The return on the last dollar tells you what more budget would earn. Without it, budget negotiations are about opinions.

Where to go next