Step 8 of 10

Migration paths

Time: Varies by source system
Prerequisites: Familiarity with your current routing system, a Restormel Keys account
You'll need: Access to your current gateway/proxy config, your app's codebase, and the Dashboard

This page covers migration from four starting points: custom routing code, LiteLLM, Portkey, and OpenRouter. Each variant follows the same principle: strangler pattern — run old and new in parallel, shift traffic incrementally, verify, then retire the old system.

The walkthrough phases (0–6) are framework-agnostic. This page maps each migration source to the phases, highlights what's different, and provides source-specific prompts.

Migration principle: the strangler pattern

Your app sends 100% traffic to the old routing system (LiteLLM, Portkey, or custom). A feature flag gates Restormel Resolve; when enabled, some traffic takes the new path to the AI provider. Both paths can hit the provider until you cut over.

  1. Install Restormel Keys alongside your existing system (Phase 1). Nothing changes yet.
  2. Wire the resolve call behind a feature flag (Phase 2). Old system still handles 100%.
  3. Shift a small percentage of traffic to Restormel (Phase 6, Step 6.2). Both systems run.
  4. Verify — compare outcomes, latency, and errors between old and new paths.
  5. Cut over — move all traffic to Restormel. Old system is idle.
  6. Remove — decommission the old system after a burn-in period.

At no point do you rip out the old system before the new one is proven. The feature flag (Phase 0, Step 0.5) is your safety net throughout.

Variant A — I have custom routing code

This is the default path the walkthrough is written for. Your app has bespoke if/else, config files, or a small routing module that picks providers.

What's different: Nothing. Follow Phases 0–6 as written.

PhaseWhat you do
0Inventory your custom files (router, fallback, model picker, BYOK settings)
1Install packages, create project
2Wire resolve alongside your custom router via feature flag
3Move your fallback chain config into dashboard routes
4Move your model allowlists into dashboard policies
5Replace your custom model picker with ModelSelector
6Shift traffic, verify, remove custom code
Note — Custom routing code is often spread across many files with implicit dependencies. Phase 0 (inventory) is especially important; don't skip it.
Variant B — I'm using LiteLLM

LiteLLM is a proxy server that normalises provider APIs. You call LiteLLM's endpoint and it forwards to the configured provider. Common setup: Docker container running LiteLLM with a config file defining models, fallbacks, and provider keys.

What Restormel replaces: LiteLLM's routing and fallback logic → Restormel routes and steps. LiteLLM's model config → Restormel dashboard (routes, policies, model catalog). LiteLLM's proxy endpoint → your app calls providers directly using the resolve result.

What Restormel does NOT replace: LiteLLM's request/response normalisation if you depend on its unified schema. If you need this, keep LiteLLM as a normalisation layer and have Restormel decide which model LiteLLM should use.

PhaseLiteLLM-specific notes
0Inventory: your LiteLLM config, the Docker/process setup, and every place your app calls the LiteLLM proxy. Classify as "REMOVE" (call providers directly) or "WRAP" (keep LiteLLM as normalisation layer with Restormel doing routing).
1Install Restormel packages. No change to LiteLLM yet.
2Wire Restormel Resolve. If keeping LiteLLM: resolve returns the model, you pass it to LiteLLM. If removing: resolve returns the provider, you call the provider SDK directly.
3Translate LiteLLM fallback settings into dashboard routes. Each LiteLLM fallback model becomes a step in a Restormel route.
4Translate any LiteLLM allowed_models or budget settings into Restormel policies.
5If LiteLLM had no UI, this is net-new. If it did, replace with Restormel ModelSelector.
6Shift traffic. When 100% is on Restormel: stop the LiteLLM container, remove config, remove Docker/process config.

Implementors: See “Agent prompts for this phase” below for plan-only prompts for each migration variant.

Variant C — I'm using Portkey

Portkey is a gateway with routing, fallbacks, caching, and observability. You call Portkey's endpoint with a config header that specifies routing strategy.

What Restormel replaces: Portkey's routing configs → Restormel routes and steps. Portkey's fallback strategies → Restormel fallback_chain route mode. Portkey's model restrictions → Restormel policies.

What Restormel does NOT replace: Portkey's request caching (use a separate caching layer if needed). Portkey's observability/tracing (use your existing tracing).

PhasePortkey-specific notes
0Inventory: Portkey configs (JSON headers or API configs), the Portkey API key, every place your app calls the Portkey API or uses the Portkey SDK.
1Install Restormel packages alongside Portkey.
2Wire Restormel Resolve. Your app calls resolve first, then makes the provider call directly. Feature flag gates which path runs.
3Translate Portkey routing configs (provider order, fallback strategy) into dashboard routes with steps.
4Translate any Portkey model restrictions or budget controls into Restormel policies.
5Embed Restormel UI. Portkey has no embeddable BYOK UI — this is net-new.
6Shift traffic. When 100% is on Restormel: remove Portkey SDK, delete Portkey API key, cancel Portkey subscription if applicable.

Key difference from LiteLLM: Portkey configs are typically JSON objects passed as headers or configured via their dashboard/SDK. Extract the routing logic from those configs manually.

Variant D — I'm using OpenRouter

OpenRouter is a unified API that routes requests to multiple providers with a single endpoint. You call the OpenRouter API with a model name, and OpenRouter handles provider selection.

What Restormel replaces: OpenRouter's implicit provider routing → Restormel explicit routes and steps (you control exactly which provider handles each model). OpenRouter's model selection → Restormel ModelSelector with policy constraints.

What Restormel does NOT replace: OpenRouter's access to providers you don't have direct accounts with. If you use OpenRouter for that, you may keep OpenRouter as a provider within Restormel's routing (a step in a route that calls OpenRouter).

PhaseOpenRouter-specific notes
0Inventory: every place your app calls the OpenRouter API, the OpenRouter API key, any model-specific logic.
1Install Restormel packages. Set up direct provider accounts (OpenAI, Anthropic, Google) for the models you use — or keep OpenRouter as a "provider" in your route.
2Wire resolve. The resolve result tells you which provider to call. If keeping OpenRouter as a provider, add it as a custom provider in your config.
3Create routes. If you previously relied on OpenRouter to pick the cheapest provider for a given model, replicate that as explicit route steps.
4Add policies. OpenRouter has no policy concept — this is net-new governance.
5Embed ModelSelector. OpenRouter has no embeddable UI — this is net-new.
6Shift traffic. When 100% is on Restormel: remove OpenRouter SDK/API calls, revoke OpenRouter API key if no longer needed.

Key difference: OpenRouter abstracts away provider choice entirely. Moving to Restormel means you take explicit control of which provider handles each request. More work, but full visibility and policy control.

Comparison: what each source gives you that Restormel doesn't
FeatureLiteLLMPortkeyOpenRouterRestormel approach
Request/response normalisationYes (proxy)Yes (proxy)Yes (proxy)No — call providers directly with their SDKs. Use Restormel for routing only.
Request cachingPluginYesNoNot in scope — use a caching layer (Redis, CDN, etc.)
Observability / tracingPluginYesBasicNot in scope — use your existing tracing
Access to providers you don't have accounts withNoNoYesNo — you need direct provider accounts (or keep OpenRouter as a step)
Embeddable BYOK UINoNoNoYes — KeyManager, ModelSelector
Policy enforcement (allowlists, budgets)PartialPartialNoYes — first-class policies in the dashboard
Library-first (no proxy/container)SDK onlyNoNoYes — headless core, no infrastructure required
The safe strangler approach in detail

Regardless of your source system, the sequence is: Week 1 — install Restormel alongside the old system. Week 1–2 — wire resolve behind a feature flag. Week 2 — configure routes and policies in the dashboard. Week 2–3 — send 5% of traffic through Restormel. If errors, fix and retry at 5%; if no errors, increase to 25%, then 50%, then 100%. Burn-in for one release cycle (1–2 weeks), then remove the old system.

Timeline: Most teams complete the migration in 2–3 weeks. The burn-in period before removing the old system is typically one release cycle.

Rollback — At any point, flip the feature flag to false and 100% of traffic returns to the old system instantly. No code change, no deployment — just an env var.
Checkpoint

You now have: a clear mapping from your source system (custom, LiteLLM, Portkey, or OpenRouter) to the walkthrough phases; a strangler approach that lets you migrate incrementally with instant rollback; source-specific notes on what Restormel replaces and what it doesn't; and (if LiteLLM) a build-agent prompt for producing a migration plan document.

Next: Verification strategy — ongoing checks for dashboard, CLI, and smoke tests after integration.

Prompts for this phase

These are optional and collapsed by default. Use them if you're migrating from an existing routing system with a coding agent.

Checkpoint checklist: mark each section complete as you read it.

Checklist