When Self-Hosting an Open-Weight Model Is Actually Cheaper Than an API

Quick answer: Usually the API wins. On the 30B tier, self-hosting only beats serverless above roughly 11 billion input tokens a month, and that is with one GPU, no redundancy, and only a fifth of an engineer costed in. The trillion-parameter open models are worse: vLLM's stated floor for Kimi K3 is a whole 8x B300 node, about $43,000 a month of rented GPU, so Moonshot's own API undercuts your cluster until you are pushing 19 billion tokens a month.

Last updated: August 2026

Most people arrive at this question with the arrow pointing the wrong way. Open weights do not mean cheap inference. They mean optional inference. Moonshot publishes the Kimi K3 weights and charges $3.00 per million input tokens and $15.00 per million output for its own API. DeepSeek publishes V4 Flash and charges $0.14 and $0.28. Artificial Analysis scores those two 60 and 52 on its Intelligence Index, K3 at max effort against V4 Flash 0731 at max reasoning effort. Treat those two numbers as soft: the same pair read 57 and 50 in an Artificial Analysis post from July, because the score moves with both the effort setting and index revisions. All read 11 August 2026. None of it tells you what the weights cost to run on your own metal.


That is a separate problem, and it splits hard by model size. The K3 checkpoint alone is 1.56 TB, so the minimum vLLM states is a whole 8x B300 node. GLM-5.2 ships BF16 weights that come to roughly 1.5 TB. Meta's Muse Glimmer 30B fits in a 17 GB file on one workstation card. That is the segmentation worth handing a client. Buy the trillion-parameter tier through an API. Start the on-prem conversation at the 30B tier.


Every break-even figure circulating on this topic disagrees with the others by five to ten times, because almost nobody shows the working. Here is the working. Published GPU hourly rates, published token prices, the cost lines that never make the spreadsheet, and a calculator you can point at your own traffic.


Open weights price the download, not the inference


A model's license and its API price have nothing to do with each other. Every model below ships open weights, and they span roughly 40x on blended price. The most expensive one is also the only one here whose license carries a revenue gate. What the vendors charged on 11 August 2026, read off their own pages: platform.kimi.ai, api-docs.deepseek.com, together.ai/pricing, openrouter.ai.


ModelWeights and licenseInput, $ per 1M tokensCache hit, $ per 1MOutput, $ per 1M
Kimi K3Open weights, 2.8T total, 16 of 896 routed experts per token$3.00$0.30$15.00
DeepSeek V4 ProOpen, MIT$0.435$0.003625$0.87
DeepSeek V4 FlashOpen, MIT, 284B total / 13B active$0.14$0.0028$0.28
Gemma 4 31B (Together serverless)Open, Apache 2.0, 30.7B dense$0.39n/a$0.97
Muse Glimmer 30B (OpenRouter)Open, Apache 2.0, 29.6B dense$0.35n/a$1.50
Qwen3.6-35B-A3B (OpenRouter)Open, Apache 2.0, 35B total / 3B active$0.098n/a$0.95

Blend those at the 7:2:1 cache-hit to cache-miss to output mix Artificial Analysis uses and K3 comes out at exactly $2.31 per million tokens, DeepSeek V4 Flash at $0.058. Close to a 40x spread between two open-weight models eight index points apart. If your reason for looking at self-hosting is the bill, changing model is the bigger lever, and it takes an afternoon rather than a quarter.


One caveat on DeepSeek. Their API docs carry a standing notice that they plan to raise overall pricing in the near future, with a significant increase expected. That is the vendor's own wording, and it has sat there for months without a date. Do not build a three-year case on $0.14.


What the trillion-parameter tier actually costs to serve


Kimi K3 ships in native MXFP4 with MXFP8 activations. The Hugging Face repo is 96 safetensors shards, about 1,561 GB decimal, 1.42 TiB. That single number decides your topology, and topology decides everything else.



Price the cheap version. Eight B300s at RunPod's Secure Cloud on-demand rate of $7.39 per GPU-hour, read 11 August 2026, is $59.12 an hour, about $43,158 a month. Against K3's blended $2.31 per million tokens you need roughly 18.7 billion tokens a month to cover the rent alone. The 16x B200 route is worse: $5.89 a card is $94.24 an hour, about $68,795 a month, and 29.8 billion tokens to break even. No engineer costed in, no fabric costed in, and you cannot generally rent a coherent multi-node allocation at single-GPU on-demand prices anyway.


GLM-5.2 is the same story one notch down. The Hugging Face card's safetensors metadata totals 753B parameters; vLLM's own recipe describes the model as roughly 743B total with 39B active. Either figure puts it near 1.5 TB at BF16 and roughly 750 GB at FP8, which does fit the single 8x H200 node the vLLM recipe targets. Eight H200s at $4.39 is $35.12 an hour, about $25,638 a month.


The tier where self-hosting is a real conversation


Below about 40B parameters the hardware story changes completely. One GPU. No interconnect, no multi-node scheduler, no fabric to debug at 3am. Three models landed in that band during 2026.


ModelParametersContextShips atFits on
Muse Glimmer 30B (Meta)29.6B dense, includes vision encoder131,0724-bit K-Quant, 17 GB file24 GB card at 1.0% degradation, 32 GB at 0.2%, 64 GB at BF16
Gemma 4 31B (Google)30.7B dense262,144BF16 weights, FP8 on Together80 GB card at FP8, roughly 16 GB at 4-bit
Qwen3.6-35B-A3B (Alibaba)35B total, 3B active MoE262,144 nativeBF16Roughly 70 GB at BF16, comfortably one card quantized

The Muse Glimmer degradation figures come from Meta's model card, which is a good template for how this should be published: both quants named, 0.2% and 1.0% against BF16 averaged over 15 benchmarks, and the memory envelope each targets. Vendor claim, not independent measurement, but falsifiable. On accuracy, Meta publishes 76.0 on SWE-bench Verified and 83.5 on GPQA Diamond for Glimmer; Google publishes 85.2 on MMLU-Pro and 84.3 on GPQA Diamond for Gemma 4 31B. Both self-reported, neither independently replicated at the time of writing, and none of it is a throughput number, which is the only figure your cost model actually needs.


This is the tier where I would let a client run the numbers. Everything above it, I would not.


Bill climbing faster than usage? The overspend is usually in a handful of places: warehouses that never suspend, one query pattern nobody revisited, and clustering that was never measured. We go through the account and hand back the fixes with the credits each one saves attached.

Book a cost review Model your Snowflake spend

The break-even, with the working shown


You want both sides from one vendor, otherwise you are pitting somebody's loss-leader token price against somebody else's list-price GPU. Together AI publishes both: Gemma 4 31B serverless at $0.39 in and $0.97 out per million tokens, and dedicated capacity at $5.49 per H100 per hour. The specialist clouds set a cheaper floor.


ProviderGPU$/GPU-hour$/GPU-month (730h)
RunPod Secure CloudH100 SXM 80GB$2.99$2,182.70
RunPod Secure CloudH200 SXM 141GB$4.39$3,204.70
RunPod Secure CloudB200 180GB$5.89$4,299.70
RunPod Secure CloudB300 288GB$7.39$5,394.70
Lambda (8x instance)H100 SXM$3.99$2,912.70
Lambda (8x instance)B200 SXM6$6.69$4,883.70
Together dedicatedHGX H100$5.49$4,007.70
Together dedicatedHGX B200$8.99$6,562.70

All read 11 August 2026, on-demand only. Spot rates are excluded: they move weekly and you cannot run production on capacity that evaporates mid-request. Take the cheapest credible H100 line, RunPod at $2.99. Assume a 10:1 input-to-output mix, roughly what a retrieval-heavy app or a coding agent looks like.


ScenarioFixed monthly costBreak-even volumeSustained rate that implies
1x H100, no redundancy, nobody paid to run it$2,332.704.79B input + 0.48B output1,823 input tok/s, every second, 24/7
Same, plus 20% of one senior engineer$5,666.0311.63B input + 1.16B output4,427 input tok/s, every second, 24/7
Same, plus a second H100 for failover$7,848.7316.12B input + 1.61B output6,133 input tok/s on the one active GPU

The engineer is the line that flips the verdict, and it is the line that gets left out. On GPU rent alone the break-even sits near 1,800 input tokens a second sustained, which is a plausible ask of one H100 serving a 31B model at FP8. Measure it on your own traffic before believing it, including mine. Add a fifth of one person and you need 4,400 a second, forever, at 100% duty cycle. Add the second GPU that keeps a 2am driver crash from being an outage and you need 6,100 through one active card. That is not an inference platform, it is a dare.


Picture 11.6 billion input tokens a month. At 8,000 tokens of context per call that is 1.45 million calls, roughly 48,000 a day. For a coding agent chewing 40,000 tokens a turn it is 290,000 turns. If your client is not doing that, no amount of GPU shopping changes the answer.


The cost lines that never make it into the spreadsheet


Four of these, roughly in order of surprise.



A fifth item is not a cost but behaves like one: you give up changing model with a config edit. When something better ships in November, the API user edits a string. You re-run capacity planning.


The KV cache is what breaks capacity plans


Weights are the number everybody quotes. The KV cache decides how many users fit on the card. It scales with concurrency times context length, it does not shrink when you quantize, and at long context it can be several times larger than the model.


The formula is simple: 2 (for K and V) x layers x KV heads x head dimension x 2 bytes, per token. What varies wildly is what you multiply. Values below read from the published configs.


Gemma 4 31BMuse Glimmer 30B
Layers6052
KV heads162
Head dimension256128
Attention pattern5 sliding (1,024) to 1 full3 sliding (2,048) to 1 full
Full-attention layers1013
KV per token on the growing layers160 KiB13 KiB
KV for one 32,768-token sequence6.21 GB0.52 GB
KV at full native context43.79 GB at 262,1441.83 GB at 131,072
Concurrent 32K sequences on one 80GB H1007113

Both concurrency figures assume weights resident: Gemma at FP8 (30.7 GB), Glimmer at its 17 GB 4-bit quant, 4 GB for CUDA graphs, activations and allocator fragmentation. Sixteen times the concurrency on identical hardware, from two models about a billion parameters apart. Gemma 4 buys long-context quality with 16 KV heads and a 256-wide head dimension. Muse Glimmer buys throughput with 2 KV heads and aggressive sliding windows. Size a box from parameter count and you will be wrong by 16x, in production.


The cache also stays in BF16, so quantizing weights to 4-bit does nothing for it. You can switch on FP8 KV cache in vLLM and halve it, but run your evals against that first. It is a real accuracy tradeoff, not a free win.


Python - KV cache and concurrency from published config.json values
#!/usr/bin/env python3
"""KV cache VRAM straight from a model config.json.
Values below were read from google/gemma-4-31B-it and
meta-models/Muse-Glimmer-30B on 11 August 2026."""

GB = 1e9   # decimal, to match how vendors quote VRAM


def kv_bytes_per_seq(n_layers, kv_heads, head_dim, ctx,
                     sliding_window=None, sliding_ratio=0, dtype_bytes=2):
    """sliding_ratio = sliding layers per full-attention layer, so 5 encodes
    the 5:1 pattern in Gemma 4. dtype_bytes stays at 2: the KV cache is BF16
    regardless of how hard you quantized the weights, unless you explicitly
    enable FP8 KV and accept the accuracy cost."""
    per_layer_per_token = 2 * kv_heads * head_dim * dtype_bytes   # K and V
    full_layers = n_layers // (sliding_ratio + 1)
    sliding_layers = n_layers - full_layers

    total = full_layers * per_layer_per_token * ctx
    if sliding_window:
        total += sliding_layers * per_layer_per_token * min(ctx, sliding_window)
    else:
        total += sliding_layers * per_layer_per_token * ctx
    return total


# layers, kv_heads, head_dim, sliding_window, sliding_ratio, max_ctx, weights
MODELS = {
    "Gemma 4 31B (FP8)":     (60, 16, 256, 1024, 5, 262144, 30.7 * GB),
    "Muse Glimmer 30B (4b)": (52,  2, 128, 2048, 3, 131072, 17.0 * GB),
}

H100_80GB = 80 * GB
RUNTIME_OVERHEAD = 4 * GB   # CUDA graphs, activations, allocator fragmentation

for name, (L, kvh, hd, win, ratio, max_ctx, weights) in MODELS.items():
    for ctx in (32768, max_ctx):
        per_seq = kv_bytes_per_seq(L, kvh, hd, ctx, win, ratio)
        free = H100_80GB - weights - RUNTIME_OVERHEAD
        print(f"{name:23s} ctx={ctx:>6}  {per_seq/GB:6.2f} GB/seq  "
              f"{int(free // per_seq):>4} concurrent on one 80GB H100")

# Gemma 4 31B (FP8)       ctx= 32768    6.21 GB/seq     7 concurrent on one 80GB H100
# Gemma 4 31B (FP8)       ctx=262144   43.79 GB/seq     1 concurrent on one 80GB H100
# Muse Glimmer 30B (4b)   ctx= 32768    0.52 GB/seq   113 concurrent on one 80GB H100
# Muse Glimmer 30B (4b)   ctx=131072    1.83 GB/seq    32 concurrent on one 80GB H100

4-bit stopped being a community afterthought


The reason the numbers above are not far worse is that frontier open models now ship quantized by the lab that trained them. K3's MXFP4 weights are quantization-aware trained from the supervised fine-tuning stage onward, not converted afterwards. DeepSeek's V4 Flash card puts its MoE experts in FP4 and most other parameters in FP8. These are not community GGUFs made after the fact.


The consequence is arithmetic. 2.8 trillion parameters at BF16 would be 5.6 TB. At four bits plus block scales, K3's checkpoint is 1.56 TB. That is the difference between a deployment that fits one Blackwell node and one that would need three. It also retires the reflex of penalizing quantized weights on quality: this is what the lab trained and what the lab benchmarked.


The old caution still applies to community quants of models that shipped BF16. Unsloth's 2-bit UD-IQ2_M of GLM-5.2 is a 239 GB file wanting about 245 GB of combined RAM and VRAM, and Unsloth's own figure puts it near 82% of the full model's accuracy. That is a usable number and an honest one, but it is still a different model from the one on the benchmark table, and nobody has run your evals against it.


A calculator you can run on your own numbers


Take the structure, not my scenario, and put your own traffic in it. This reproduces every figure in the break-even table above.


Python - break-even calculator, reproduces the table above
#!/usr/bin/env python3
"""Break-even: a rented GPU vs serverless tokens.
Every price hard-coded below was read from a vendor page on 11 August 2026.
Change them. They move."""

HOURS_PER_MONTH = 730                      # 365 * 24 / 12
SECONDS_PER_MONTH = HOURS_PER_MONTH * 3600 # 2,628,000


def monthly_selfhost(gpu_hourly, gpu_count, engineer_fraction,
                     engineer_loaded_annual, platform_fixed):
    gpu = gpu_hourly * gpu_count * HOURS_PER_MONTH
    people = engineer_fraction * engineer_loaded_annual / 12
    return gpu + people + platform_fixed


def breakeven_tokens(monthly_cost, price_in_per_m, price_out_per_m, out_ratio):
    """out_ratio = output tokens per input token. 0.10 is a 10:1 RAG-ish mix."""
    cost_per_m_input = price_in_per_m + out_ratio * price_out_per_m
    m_input = monthly_cost / cost_per_m_input
    return m_input * 1e6, m_input * out_ratio * 1e6


def sustained_rate(tokens_per_month, active_gpus=1):
    return tokens_per_month / SECONDS_PER_MONTH / active_gpus


if __name__ == "__main__":
    # Gemma 4 31B on Together AI serverless: $0.39 in / $0.97 out per 1M tokens.
    API_IN, API_OUT, OUT_RATIO = 0.39, 0.97, 0.10
    GPU_HOURLY = 2.99      # H100 SXM 80GB, RunPod Secure Cloud, on-demand

    scenarios = [
        ("GPU rent only",        1, 0.00),
        ("+ 20% of an engineer", 1, 0.20),
        ("+ failover GPU",       2, 0.20),
    ]

    for label, gpus, eng in scenarios:
        cost = monthly_selfhost(
            gpu_hourly=GPU_HOURLY,
            gpu_count=gpus,
            engineer_fraction=eng,
            engineer_loaded_annual=200_000,  # fully loaded. Plug in your own.
            platform_fixed=150,              # registry, logs, metrics, images
        )
        t_in, t_out = breakeven_tokens(cost, API_IN, API_OUT, OUT_RATIO)
        print(f"{label:22s} ${cost:9,.2f}/mo   "
              f"{t_in/1e9:5.2f}B in + {t_out/1e9:4.2f}B out   "
              f"{sustained_rate(t_in):6,.0f} input tok/s sustained, 24/7")

# GPU rent only          $ 2,332.70/mo    4.79B in + 0.48B out    1,823 input tok/s sustained, 24/7
# + 20% of an engineer   $ 5,666.03/mo   11.63B in + 1.16B out    4,427 input tok/s sustained, 24/7
# + failover GPU         $ 7,848.73/mo   16.12B in + 1.61B out    6,133 input tok/s sustained, 24/7

The one input you cannot read off a pricing page is your own throughput, and it is the one everybody guesses. Published tokens-per-second figures are third-party and workload-dependent, shifting with the vLLM version, the card revision, the sequence length distribution and the batch shape. SGLang and vLLM trade the lead depending which you hold fixed.


bash - serve it, then measure it instead of trusting a benchmark blog
# Serve Gemma 4 31B at FP8 on a single H100 and find out what the box does.
vllm serve google/gemma-4-31B-it \
  --quantization fp8 \
  --max-model-len 32768 \
  --gpu-memory-utilization 0.92 \
  --max-num-seqs 8 \
  --enable-prefix-caching

# Now measure it. Do not trust anyone else's tokens/sec figure, mine included.
# Set the lengths from your own traffic. 512/512 flatters every serving stack.
vllm bench serve \
  --model google/gemma-4-31B-it \
  --dataset-name random \
  --random-input-len 8000 \
  --random-output-len 800 \
  --num-prompts 200 \
  --request-rate 4

# The only number that matters falls out of that run:
#   cost per 1M output tokens = monthly_gpu_bill / (output_tok_s * 2628000 / 1e6)
# 2628000 is the number of seconds in a 730-hour month.
# Compare it to the API price. If you are not at least 2x cheaper, buy tokens.

The four honest reasons to self-host


Cost is rarely one. These four are, and I have seen each justify a deployment the spreadsheet argued against.



None of those is the bill. A client who leads with cost is usually about to spend six months of engineering to save nothing. A client who leads with residency is worth talking to on day one.


What I would actually build


For a mid-market client with a normal workload the recommendation is negative. Do not self-host. Route to a serverless open-weight model, keep the provider abstraction thin enough that swapping takes an afternoon, and revisit in two quarters with real volume data. That advice costs me revenue and it is still right.


If residency forces your hand, start at the 30B tier and nowhere else. Muse Glimmer 30B on a 32 GB card when agentic tool use and screenshot reading are in scope. Gemma 4 31B when you need 256K context and can live with the KV arithmetic above. Qwen3.6-35B-A3B when coding throughput is the priority. One GPU, vLLM or SGLang, prefix caching on, and a hard --max-model-len set from your measured p99 prompt length rather than the model's maximum. That last setting is the biggest lever on how many users fit, and almost nobody touches it.


And if somebody wants to self-host Kimi K3 because the weights are free: they are 1.56 TB, vLLM's minimum serving unit is a whole 8x B300 node, and Moonshot sells the same model at $3.00 and $15.00 per million tokens with a 1,048,576-token window and a flat rate at any context length. Free weights, roughly $43,000 a month of rent.


Pranay Vatsal, Founder & CEO

Pranay Vatsal is the Founder & CEO of CelestInfo with deep expertise in Snowflake, data architecture, and building production-grade data systems for global enterprises.

Related Articles

Frequently Asked Questions

Q: Is self-hosting an LLM cheaper than using an API?

Usually not. Using published August 2026 prices, a 31B model on one rented H100 breaks even against Together's serverless rate at roughly 11.6 billion input tokens a month once you cost in 20% of an engineer. Below that the API is cheaper, and it comes with redundancy you are not paying for separately.

Q: How much GPU VRAM do I need for a 70B model?

Weights are the easy part: 140 GB at BF16, 70 GB at FP8, about 35 GB at 4-bit. So one 80 GB H100 at 4-bit, or two at FP8. The KV cache decides whether that is actually usable. Budget 20 to 40 GB more for concurrent long-context requests, depending on the model's KV head count.

Q: Can I self-host Kimi K3?

Only on Blackwell-class hardware, or across a multi-node cluster. The MXFP4 checkpoint is about 1,561 GB across 96 safetensors shards. One 8x H200 node holds 1,128 GB and a DGX B200 node holds 1,440 GB, so neither fits. vLLM states a minimum of one 8x B300 node at 2,304 GB or a GB300 NVL72, and also supports 16x B200 across two nodes with an RDMA or NVLink all-to-all backend.

Q: How much VRAM does the KV cache use?

It is 2 x layers x KV heads x head dimension x 2 bytes per token, times concurrency. For Gemma 4 31B that works out at 160 KiB per token on its full-attention layers, so 6.2 GB for one 32K sequence. For Muse Glimmer 30B it is 13 KiB, so 0.52 GB. Same size class, twelve times the difference.

Q: Does quantizing to 4-bit reduce KV cache memory?

No. Weight quantization and KV cache precision are independent settings. The cache stays in BF16 unless you explicitly enable FP8 KV cache in vLLM or SGLang, which halves it at some accuracy cost. Run your evals before shipping that. At long context the cache can exceed the quantized weights several times over.

Q: What token volume justifies a dedicated GPU endpoint?

For a 30B-class model on a $2.99 per hour H100, roughly 11 to 16 billion input tokens a month, depending on whether you fund redundancy. That is around 4,400 input tokens per second sustained around the clock. If your traffic is business hours only, you need triple that peak rate to reach the same monthly total.