Contents
Prepare before the email, then baseline, tune, shadow, canary, retire — in that order, every time
The email arrives on a quiet Tuesday: "We're retiring the model you depend on." You read it twice, check the date, and realize your whole product runs on a model with a countdown clock.
I got that email last year. We had hardcoded the model name in 14 places, our prompts had grown around the old model's quirks, and nobody remembered which features used what. We made the deadline, but my sleep schedule didn't recover for a week.
This guide shows you how to handle LLM model migration and provider deprecations calmly. You'll learn how to prepare before the email lands and how to swap models without breaking your app — the versioning discipline the prompt versioning guide applies to prompts, applied to models.
Why Model Migrations Hurt
Swapping a model sounds like changing one string. It never works that way. A new model behaves differently, even when the provider calls it an upgrade.
Here's what typically shifts:
- Output style: tone, verbosity, and formatting change.
- Instruction following: the new model reads your prompt differently, so old tricks stop working.
- Structured output: JSON habits, schema adherence, and tool-calling behavior vary.
- Refusals and safety: borderline requests may flip in either direction.
- Latency and cost: speed and pricing rarely match the old model.
- Context and limits: window sizes, token counts, and rate limits differ.
Your app depends on all of these without you realizing it. Ever wonder why a "better" model can make your product worse? This is why.
Prepare Before the Deprecation Email
The best migration starts months before anyone announces a shutdown. Build these habits now, and the email becomes a mild inconvenience.
Keep a Model Inventory
Write down every place your app calls a model. For each one, record the feature, the model name, the prompt version, and the owner. If you can't answer "what uses model X?" in one minute, you have homework.
Put Model Names in Config
Hardcoded model names scatter across your codebase like glitter. Move them into one config file keyed by feature. Then a migration becomes a config change plus testing, not a treasure hunt:
# models.yaml
features:
support_chat:
primary: model-large-v2
fallback: model-medium-v2
params: {temperature: 0.2, max_tokens: 800}
summarize:
primary: model-small-v3
params: {temperature: 0.0, max_tokens: 400}
Pin Exact Versions
Avoid floating aliases that silently point to new models. Pin a specific version in production so behavior changes only when you decide. Aliases save effort until the day they cost you a weekend.
Build an Abstraction Layer
Wrap provider calls behind a thin interface in your own code. Your features call generate(feature, input), and the layer handles provider-specific details. IMO, this single decision saves more migration pain than any other — and it's exactly what LiteLLM's unified API gives you out of the box.
Track Deprecation Notices
Subscribe to your provider's changelog and deprecation announcements. Send them to a shared channel, not one person's inbox. Add retirement dates to your team calendar, with reminders 90, 60, and 30 days out.
Own a Real Eval Suite
You can't judge a new model by vibes. You need a regression suite that says whether quality held up. Build it from these pieces:
- Golden dataset: 50 to 200 real prompts with defined success criteria.
- Deterministic checks: schema validity, required fields, length limits, and banned phrases.
- Pairwise judge: a model that compares old and new answers and picks the better one.
- Cost and latency tracking: numbers you compare side by side.
FYI: teams that own this suite finish migrations in days. Teams without it argue about screenshots for weeks — the same four-layer stack the CI/CD guide wires into every deploy.
The Migration Playbook
When a deprecation lands, follow the same sequence every time. Repetition makes it boring, and boring is perfect.
Step 1: Read the Fine Print
Check the retirement date, the suggested replacement, and any changes to the API. Some replacements change request formats, parameters, or token limits. Know what you face before you start.
Step 2: Choose Candidates
Don't accept the suggested replacement automatically. Shortlist two or three candidates, including the recommended one and maybe a different size or vendor. Compare them on quality, speed, and price.
Step 3: Run Baseline Evals
Run your suite against the old model first, then each candidate with your existing prompts unchanged. This shows the raw gap before you tune anything. Review the worst failures by hand, since patterns jump out quickly:
old = run_suite(config["support_chat"]["primary"], golden) # today's model first
for name in ("model-large-v3", "model-medium-v3", "other-vendor-v2"):
new = run_suite(name, golden) # prompts unchanged
print(name, {
"pass_delta": new.pass_rate - old.pass_rate, # quality held?
"cost_delta": new.cost_per_case - old.cost_per_case,
"regressions": worst_regressions(old, new)[:5], # read these by hand
})
Step 4: Adapt Your Prompts
Now tune. Common fixes include:
- Loosen overly rigid instructions that the new model follows too literally.
- Tighten vague instructions that the old model guessed correctly.
- Rework few-shot examples to match the new model's style.
- Adjust parameters like temperature and max tokens, because defaults differ.
- Update tool and schema definitions if the new model handles them differently.
Change one thing at a time and rerun your evals. Prompt tuning without measurement is just superstition.
Step 5: Run Shadow Mode
Send real traffic to the new model quietly, and keep serving the old model's answers. Compare outputs offline. Shadow mode shows how the new model handles the messy inputs your test set missed.
Figure 1: Old answers beside new ones — shadow mode finds the regressions your golden set never imagined
Step 6: Release a Canary
Route a small share of live traffic, say 5%, to the new model. Watch your primary metric and your guardrails: errors, latency, cost, refusals, and user feedback. Widen the rollout in stages if everything looks healthy.
Step 7: Roll Out and Retire
Shift remaining traffic once the canary proves itself. Keep a fast rollback path for a while, then delete the old model from your config and code. Don't leave dead references behind, because they confuse the next migration.
Handle the Tricky Details
Some migration problems hide until production. Check these on purpose:
- Tokenization differences: the same text can use more or fewer tokens, which changes costs and context limits.
- Rate limits: a new model often carries different limits. Check capacity before you shift full traffic.
- Streaming behavior: chunk sizes and timing can change your UI's feel.
- Structured output reliability: test malformed JSON rates, not only happy-path samples.
- Long-context behavior: models vary in how well they use long inputs.
- Downstream parsers: anything that parses model output may break on small formatting shifts.
Build Safety Nets
Even a careful migration surprises you sometimes. Prepare for that:
- Fallback model: route to an alternative if the primary fails repeatedly.
- Feature flags: flip a switch to revert without a deploy.
- Alerts: watch error rate, latency, cost per request, and feedback scores after the switch.
- Output validation: reject and retry malformed responses before users see them.
A rollback you tested beats a rollback you hope works.
Plan the Timeline Realistically
Deadlines look generous until you start. Work backward from the retirement date and pad generously:
- Weeks 1 to 2: inventory, read notices, pick candidates, run baseline evals.
- Weeks 3 to 4: tune prompts, fix regressions, validate costs and limits.
- Weeks 5 to 6: shadow mode, then canary.
- Final weeks: full rollout, cleanup, and buffer for surprises.
Start the moment you hear about a deprecation. Waiting "until things calm down" never works, because things never calm down.
Communicate Early and Often
Migrations touch more than engineering. Tell product, support, and leadership what's changing and when. Warn them that tone and phrasing may shift slightly, so nobody panics when the bot sounds a little different.
Write a short migration note for each feature: old model, new model, test results, known differences. Future you will appreciate that document more than present you expects.
Mistakes I Made So You Don't Have To
Here's my regret list:
- Hardcoding model names everywhere. One migration meant 14 separate edits and two missed spots.
- Trusting the vendor's "drop-in replacement" claim. It wasn't, and our JSON parser noticed first.
- Skipping the cost check. The new model produced longer answers, and our bill crept up.
- Waiting too long. I started the work three weeks before the deadline and regretted every day.
Common Pitfalls
- String-swap migrations — the new model reads your prompts differently; measure, don't assume.
- Floating aliases in production — behavior changes with no commit from you; pin exact versions.
- No model inventory — feature-to-model mapping discovered mid-deadline is a treasure hunt.
- Eval-less opinions — "feels better" arguments cost weeks; a golden set decides in hours.
- Tuning many things at once — one change per eval run or you learn nothing from the delta.
- Skipping shadow and canary — messy real inputs only exist in production traffic.
- "Drop-in replacement" trust — vendors test their API, not your JSON parser.
- Dead references after cleanup — old model names left behind confuse the next migration.
Best Book to Read
| Cover | Book | Description | Get it |
|---|---|---|---|
![]() |
Continuous Delivery | the staged-rollout canon this playbook follows: baseline, canary, rapid rollback, and routine, boring releases. | View on Amazon |
![]() |
Designing Machine Learning Systems | model versioning, monitoring, and the eval-first posture that makes swaps survivable. | View on Amazon |
![]() |
AI Engineering | comparing candidate models on your own tasks, judge-based evaluation, and cost-quality trade-offs. | View on Amazon |
![]() |
Building LLM Powered Applications | provider abstraction and config-driven model routing, the layer that makes the next migration a config edit. | View on Amazon |
As an Amazon Associate I earn from qualifying purchases. Links on this page are affiliate links, and I may earn a commission at no extra cost to you.
Unlock AI That Actually Works
Get lifetime access to GPT-6 Astra, Claude Fable 5.1, Gemini 3.5, Grok 4.5, and more — all in one platform. Build websites, apps, videos, content, and digital products from a single command. No monthly fees. No tool-hopping.
Click here to get GPTAstra Max now — one-time payment, lifetime access.
Frequently Asked Questions
Why does swapping an LLM model break apps?
Because a new model behaves differently even when the provider calls it an upgrade. Output style shifts (tone, verbosity, formatting), instruction following changes so old prompt tricks stop working, structured output varies (JSON habits, schema adherence, tool-calling), refusals on borderline requests can flip in either direction, latency and cost rarely match, and context windows, token counts, and rate limits differ. Your app depends on all of these without you realizing it — which is why a "better" model can make a product worse. The fix is treating migration as a measured change: inventory, config, baseline evals, and staged rollout instead of a string replacement.
How do you prepare before a deprecation email lands?
Build the habits months ahead. Keep a model inventory recording the feature, model name, prompt version, and owner for every call site — if "what uses model X?" takes more than a minute to answer, you have homework. Move hardcoded model names into one config file keyed by feature, so migration becomes a config change plus testing. Pin exact versions in production instead of floating aliases that silently point at new models. Wrap provider calls behind a thin abstraction layer so features call generate(feature, input) and the layer handles provider details. Subscribe to the provider's changelog in a shared channel with 90/60/30-day reminders. And own an eval suite: a 50–200 prompt golden dataset with success criteria, deterministic checks, a pairwise judge, and cost/latency tracking — teams with it finish in days, teams without it argue about screenshots for weeks.
What's the step-by-step migration playbook?
Seven steps, the same sequence every time. 1) Read the fine print: retirement date, suggested replacement, API changes to formats, parameters, or token limits. 2) Choose candidates: don't auto-accept the recommendation; shortlist two or three across quality, speed, and price, including a different size or vendor. 3) Run baseline evals: old model first, then each candidate with prompts unchanged, to see the raw gap — review the worst failures by hand. 4) Adapt prompts: loosen rigid instructions, tighten vague ones, rework few-shot examples, adjust temperature and max_tokens, update tool schemas — one change at a time, rerunning evals, because tuning without measurement is superstition. 5) Shadow mode: real traffic to the new model quietly while serving old answers, compared offline. 6) Canary: ~5% live traffic watching errors, latency, cost, refusals, and feedback, widening in stages. 7) Roll out, keep rollback fast, then delete old model references.
What details break LLM migrations in production?
The ones you don't check on purpose: tokenization differences that change costs and context limits; new rate limits — verify capacity before shifting full traffic; streaming chunk sizes and timing that alter your UI's feel; structured output reliability — measure malformed JSON rates, not happy-path samples; long-context behavior, which varies widely; and downstream parsers that break on small formatting shifts. Build safety nets before you need them: a fallback model routed on repeated failure, feature flags so you can revert without a deploy, alerts on error rate, latency, cost per request, and feedback scores, and output validation that rejects and retries malformed responses before users see them. Work backward from the retirement date across roughly six padded weeks, and start the day you hear — things never calm down.
Wrapping This Up
Providers will retire models, and you can't stop that. You can make it routine. Keep model names in config, pin versions, own a real eval suite, and follow the same playbook each time: baseline, tune, shadow, canary, retire.
Start with the inventory this week. When the next deprecation email arrives, you'll read it, shrug, and open your checklist instead of your panic.



