> ## Documentation Index
> Fetch the complete documentation index at: https://gomodel-build-canonical-module-path.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Virtual Models

> Use GoModel virtual models to expose stable model names and test model swaps without changing app code.

<img src="https://mintcdn.com/gomodel-build-canonical-module-path/cDiuvZtU5AlmEDf_/features/virtual-models.png?fit=max&auto=format&n=cDiuvZtU5AlmEDf_&q=85&s=081fa0a73da9257b98f3ca5f2f841feb" alt="GoModel dashboard models page with the New virtual model button and an active redirect row" style={{ width: "100%", maxWidth: "1280px", height: "auto" }} className="rounded-lg" width="1600" height="636" data-path="features/virtual-models.png" />

## What virtual models do

A virtual model is a model you define, instead of one a provider advertises.
GoModel picks the kind from whether you give it a target:

* A **redirect** (an alias) is a stable name that points to a concrete provider
  model. Your app sends the name in the `model` field, and GoModel resolves it
  before sending the request upstream.
* An **access policy** has no target. It gates an existing model selector by
  `user_path` — or disables it entirely — without adding a new name. See
  [User Path](/features/user-path#model-access) for access control.

Create and manage both in the admin dashboard at `Models -> New virtual model`.
Fill **Target model** to make a redirect; leave it empty to make an access
policy on the **Source** selector.

The rest of this page covers redirects.

## Use stable names

You can expose names like `regular` and `smarter` instead of provider-specific
model IDs.

* `regular` -> `anthropic/claude-sonnet-4-6`
* `smarter` -> `anthropic/claude-opus-4-6`

Your app can then send:

```json theme={null}
{
  "model": "regular",
  "messages": []
}
```

## Load balance across models

A redirect can point at **several** target models and spread requests across
them. Add more than one target in the editor (**Add target**) and pick a
**strategy**:

* **Round-robin** (default) rotates requests evenly across the targets. Set a
  per-target **weight** to bias the share — a target with weight `2` receives
  twice the traffic of a target with weight `1`.
* **Lowest cost** routes every request to the cheapest currently-available
  target, ranked by the model registry's input + output per-token price. When a
  target has no registry pricing it is skipped while a priced target exists; if
  none are priced, the first listed target is used.

Targets that the gateway cannot currently serve (unknown model, provider down)
are skipped automatically, so a redirect keeps working as long as one target is
available. A redirect with a single target behaves exactly like a plain alias.

```json theme={null}
{
  "model": "smart",
  "messages": []
}
```

For example, point `smart` at both `openai/gpt-4o` and `anthropic/claude-sonnet-4-6`
with the round-robin strategy to split load, or at a premium and a budget model
with the cost strategy to always take the cheaper one.

## Rename or repoint a redirect

Open a redirect in the dashboard and edit its **Source** to rename it. GoModel
moves the definition to the new name in one step — the old name stops resolving,
so update any app still sending it. Renaming onto a name that already belongs to
another virtual model is rejected; renaming onto a concrete model name shadows
that model (see [Shadow a model](#shadow-a-model)).

Redirects that shadow a model can be edited the same way — use the model row's
**Edit redirect** action. Virtual models declared as code keep their `source`
fixed in configuration; rename them by editing the declaration.

## Define virtual models as code

Operators who manage configuration as infrastructure-as-code can declare virtual
models in `config.yaml` or the `VIRTUAL_MODELS` environment variable instead of
the dashboard. Declarative entries are applied at startup, **override** any
admin-store row with the same `source`, and are shown read-only in the dashboard
(a **Config** badge). Edit the configuration to change them.

In `config.yaml`:

```yaml theme={null}
virtual_models:
  # A plain alias.
  - source: regular
    target: anthropic/claude-sonnet-4-6

  # A weighted round-robin load balancer.
  - source: smart
    strategy: round_robin
    targets:
      - model: openai/gpt-4o
        weight: 2
      - model: anthropic/claude-sonnet-4-6

  # A cost-based load balancer.
  - source: cheap
    strategy: cost
    targets:
      - { model: openai/gpt-4o }
      - { model: groq/llama-3.3-70b }
```

The same list as a single environment variable (JSON), which overrides
`config.yaml` entries with a matching `source`:

```env theme={null}
VIRTUAL_MODELS=[{"source":"smart","strategy":"cost","targets":[{"model":"openai/gpt-4o"},{"model":"groq/llama-3.3-70b"}]}]
```

Each entry accepts `source`, a single `target` (shorthand) or a `targets` list,
`strategy` (`round_robin` or `cost`), `user_paths`, `description`, and `enabled`.
Leave the targets empty to declare an access policy on the `source` selector. An
invalid declaration (unknown strategy, missing or self-referential target) fails
startup with a clear error.

## Expose only redirects

To hide provider models from `GET /v1/models`, set:

```env theme={null}
KEEP_ONLY_ALIASES_AT_MODELS_ENDPOINT=true
```

When this is enabled, GoModel returns enabled redirects from `/v1/models`
instead of the full provider model list. The setting is also listed in
`.env.template`.

## Shadow a model

A redirect can "shadow" a model by using the same name as an existing model and
pointing it somewhere else. This lets you override a requested model without
changing application code.

For example:

* source: `anthropic/claude-opus-4-6`
* target model: `anthropic/claude-sonnet-4-6`

Your app can keep sending `anthropic/claude-opus-4-6`, while GoModel routes the
request to `anthropic/claude-sonnet-4-6`.

## A/B testing

Redirects are useful for short model experiments. Move a redirect from one
target to another, then compare app behavior, latency, and usage.

For example, point `smarter` at Opus for one test and Sonnet for another. You can
also shadow `opus-4-6` with `sonnet-4-6` to check whether the same app flow still
works.
