Before understanding Virtual Models, understand why they exist.
The old way:
anthropic/claude-opus-5.5The core pain points:
| Problem | Impact |
|---|---|
| Model string is hardcoded | Every change needs a redeploy |
| No central control | Different apps may use inconsistent settings |
| Security settings can be overridden | Callers can bypass Zero Data Retention |
| Hard to track spend per task | Reporting is messy |
Think of a Virtual Model as a named pointer that sits between your app and the real model.
Your App
↓
calls "vmc/coding-agent" ← Virtual Model ID (never changes)
↓
AI Gateway reads config
↓
Routes to actual model (e.g., Claude, GPT-6) ← This CAN change
Key insight: Your app always calls the same ID. What that ID points to can change anytime, centrally, without touching your app.
vmc/vmc/coding-agent, vmc/storefront-assistantA virtual model bundles together:
anthropic/claude-opus-5.5)Virtual model settings ALWAYS win over request-level settings
This means:
vercel ai-gateway virtual-models create coding-agent \
--model anthropic/claude-opus-5.5 \
--config '{"speed":"fast","zeroDataRetention":true}'
Breaking this down:
| Part | Meaning |
|---|---|
coding-agent | The name (becomes vmc/coding-agent) |
--model | The real model it points to right now |
--config | Settings that travel with this virtual model |
import { streamText } from 'ai';
const result = streamText({
model: 'vmc/coding-agent', // ← Virtual model ID, not a real model
prompt: 'Remove the deprecated API calls from this module.',
});
Notice: The model string is vmc/coding-agent, not anthropic/claude-opus-5.5. Your code never needs to know which real model is behind it.
When a better model releases, you update the virtual model — not your app:
vercel ai-gateway virtual-models edit coding-agent \
--model openai/gpt-6.1-sol
What happens next:
vmc/coding-agent picks up the new model within minutes⚠️ Exception: Provider-specific options (like Anthropic-only settings) stop applying when you switch to an OpenAI model. Always review provider options after switching providers.
A best practice is one virtual model per task type, because different tasks have different needs:
vmc/support-triage → cheap, fast model (runs 100s of times/hour)
vmc/legal-review → expensive, high-reasoning model (runs rarely)
vmc/coding-agent → balanced model for code tasks
vmc/storefront-assistant → reliable model with strong fallbacks
Why this matters:
Never switch a production virtual model blindly. Use this pattern:
Step 1: Create a candidate virtual model
vmc/coding-agent-candidate → new model
Step 2: Run your evaluations against the candidate
Step 3: If quality is good → update vmc/coding-agent to new model
Step 4: If quality drops → point vmc/coding-agent back to old model
This gives you a safe rollback path with no code changes needed at any step.
Virtual Models solve a security and governance problem too:
| Who | Can Do |
|---|---|
| Platform/Security team | Create and edit virtual models, enforce settings |
| Developers/Apps | Call virtual model IDs, cannot override enforced settings |
Practical examples of enforcement:
zeroDataRetention: true → callers cannot set it to falseWITHOUT Virtual Models:
[App Code: "anthropic/claude-opus-5.5"] → change model = redeploy
WITH Virtual Models:
[App Code: "vmc/coding-agent"] → never changes
↓
[AI Gateway Config] → change model here, anytime, centrally
↓
[Real Model: whatever you configured]
The three core benefits to remember:
vmc/