# How to Configure Channel Model Mappings for Automatic Model Name Rewriting in AxonHub

> Learn how to configure channel model mappings in AxonHub for automatic model name rewriting. Streamline your provider requests by rewriting and restoring model names seamlessly.

- Repository: [Loop/axonhub](https://github.com/looplj/axonhub)
- Tags: how-to-guide
- Published: 2026-03-06

---

**AxonHub rewrites incoming model names before forwarding requests to providers by applying `modelMappings` defined in `ChannelSettings` or API-key profiles, then restores the original name in the response via inbound and outbound middleware.**

AxonHub is an open-source LLM gateway that normalizes requests across multiple providers. When you configure channel model mappings for automatic model name rewriting, you create aliases that translate client-facing model names into provider-specific identifiers without changing client code.

## Understanding Model Mappings in AxonHub

A **model mapping** is a bidirectional translation rule that intercepts the `model` field in LLM requests.

### What Model Mappings Do

Each mapping consists of two fields:

- **`from`**: The model name sent by the client (e.g., `gpt-4`).
- **`to`**: The actual model identifier required by the downstream provider (e.g., `claude-3-opus`).

When a request arrives, the inbound middleware `applyModelMapping` (implemented in [`internal/server/orchestrator/model_mapper.go`](https://github.com/looplj/axonhub/blob/main/internal/server/orchestrator/model_mapper.go)) checks the active API-key profile for mappings. If a match exists, the middleware replaces `req.Model` with the `to` value before forwarding the request. After the provider responds, the outbound middleware restores the original `from` value so the client remains unaware of the translation.

### Where Mappings Are Stored

Mappings can be defined in two locations, checked in this order:

1. **API-key profile level** – `APIKeyProfile.ModelMappings`
2. **Channel level** – `ChannelSettings.ModelMappings`

If no mapping exists at the API-key level, the hub falls back to the channel's own mappings.

## Configuring Model Mappings

### Channel-Level Configuration

Define mappings in the `ChannelSettings` struct located in [`internal/objects/channel.go`](https://github.com/looplj/axonhub/blob/main/internal/objects/channel.go) (lines 94-98):

```go
type ChannelSettings struct {
    // ...
    // ModelMappings add model alias for the model in the channels.
    // e.g. {"from": "deepseek-chat", "to": "deepseek/deepseek-chat"}
    ModelMappings []ModelMapping `json:"modelMappings"`
    // ...
}

```

### API-Key Profile Configuration

The same structure applies to API-key profiles. You can update these via the GraphQL API defined in [`internal/server/gql/generated.go`](https://github.com/looplj/axonhub/blob/main/internal/server/gql/generated.go) (lines 2584-2589).

## Mapping Logic and Pattern Matching

The `ModelMapper` in [`internal/server/orchestrator/model_mapper.go`](https://github.com/looplj/axonhub/blob/main/internal/server/orchestrator/model_mapper.go) handles the translation logic.

### Supported Matching Patterns

The `matchesMapping` function supports three pattern types:

- **Exact strings** – Literal match (e.g., `gpt-4` matches only `gpt-4`).
- **Wildcards** – Asterisks match any sequence (e.g., `gpt-*` matches `gpt-4`, `gpt-3.5-turbo`).
- **Regular expressions** – Full regex support via the cached `xregexp.MatchString` engine.

### The Mapping Algorithm

The core logic resides in `applyModelMapping` (lines 48-56):

```go
func (m *ModelMapper) applyModelMapping(mappings []objects.ModelMapping, model string) string {
    for _, mapping := range mappings {
        if m.matchesMapping(mapping.From, model) {
            return mapping.To          // rewrite
        }
    }
    return model                       // no match → keep original
}

```

If multiple mappings match, the first one in the slice wins.

## Model Visibility Configuration

Control how models appear in listing endpoints with two boolean flags defined in `ChannelSettings`:

- **`hideOriginalModels`** – When `true`, the downstream (`to`) model names are hidden from the model list; only client-facing aliases (`from`) appear.
- **`hideMappedModels`** – When `true`, only the provider's native model names are displayed, hiding the aliases.

These flags affect the model enumeration returned to UI and CLI clients.

## Practical Configuration Examples

### JSON Channel Definition

Configure a DeepSeek channel with model mappings via JSON:

```json
{
  "name": "deepseek-channel",
  "type": "deepseek",
  "settings": {
    "extraModelPrefix": "deepseek",
    "modelMappings": [
      { "from": "deepseek-chat", "to": "deepseek/deepseek-chat" },
      { "from": "deepseek-reasoner", "to": "deepseek/deepseek-reasoner" }
    ],
    "hideOriginalModels": false,
    "hideMappedModels": true
  }
}

```

Store this in the database via the admin UI or import using `axoncli`.

### GraphQL Mutation for API-Key Profiles

Update an API-key profile with regex-based mappings:

```graphql
mutation {
  updateAPIKeyProfile(
    id: "api-key-uuid",
    profile: {
      name: "my-profile",
      modelMappings: [
        { from: "gpt-4", to: "claude-3-opus" },
        { from: "gpt-.*", to: "claude-3-opus" }
      ]
    }
  ) { id }
}

```

The GraphQL resolver for `modelMappings` is defined in [`internal/server/gql/generated.go`](https://github.com/looplj/axonhub/blob/main/internal/server/gql/generated.go).

### Go SDK Programmatic Configuration

Create a channel with mappings using the internal objects package:

```go
import "github.com/looplj/axonhub/internal/objects"

ch := objects.Channel{
    Name: "deepseek-channel",
    Type: objects.ChannelTypeDeepseekAnthropic,
    Settings: objects.ChannelSettings{
        ModelMappings: []objects.ModelMapping{
            {From: "deepseek-chat", To: "deepseek/deepseek-chat"},
            {From: "deepseek-reasoner", To: "deepseek/deepseek-reasoner"},
        },
        HideOriginalModels: false,
        HideMappedModels:   true,
    },
}

```

Persist the channel using `biz.ChannelService.CreateChannel`.

### Runtime Middleware Flow

The following simplified excerpts from [`internal/server/orchestrator/model_mapper.go`](https://github.com/looplj/axonhub/blob/main/internal/server/orchestrator/model_mapper.go) demonstrate the actual request transformation:

Inbound request processing:

```go
func (m *apiKeyModelMappingMiddleware) OnInboundLlmRequest(ctx context.Context, req *llm.Request) (*llm.Request, error) {
    original := req.Model

    // Rewrite if mapping exists
    mapped := m.inbound.state.ModelMapper.MapModel(ctx, m.inbound.state.APIKey, original)
    if mapped != original {
        req.Model = mapped
        log.Debug(ctx, "model rewritten", log.String("from", original), log.String("to", mapped))
    }

    // Store original for outbound restoration
    m.RequestModel = original
    return req, nil
}

```

Outbound response restoration:

```go
func (m *apiKeyModelMappingMiddleware) OnOutboundLlmResponse(ctx context.Context, resp *llm.Response) (*llm.Response, error) {
    // Restore client-side name
    m.inbound.state.ModelMapper.ReplaceResponseModel(resp, m.RequestModel)
    return resp, nil
}

```

## Summary

- **Model mappings** translate client-facing model names to provider-specific identifiers using `from` and `to` fields.
- Configure mappings in `ChannelSettings.ModelMappings` ([`internal/objects/channel.go`](https://github.com/looplj/axonhub/blob/main/internal/objects/channel.go)) or `APIKeyProfile.ModelMappings` for per-key overrides.
- The `ModelMapper` in [`internal/server/orchestrator/model_mapper.go`](https://github.com/looplj/axonhub/blob/main/internal/server/orchestrator/model_mapper.go) handles inbound rewriting and outbound restoration via `applyModelMapping` and `ReplaceResponseModel`.
- Pattern matching supports exact strings, wildcards (`*`), and full regular expressions.
- Visibility flags `hideOriginalModels` and `hideMappedModels` control which names appear in model listings.

## Frequently Asked Questions

### How does AxonHub decide which mapping to apply when multiple patterns match?

AxonHub evaluates mappings in the order they appear in the `ModelMappings` slice and applies the first match found. The `applyModelMapping` function iterates sequentially through the array, so you should place more specific patterns (exact matches) before broader wildcard or regex patterns to ensure correct prioritization.

### Can I use regular expressions in the `from` field of a model mapping?

Yes, the `matchesMapping` function in [`internal/server/orchestrator/model_mapper.go`](https://github.com/looplj/axonhub/blob/main/internal/server/orchestrator/model_mapper.go) supports full regular expressions in addition to exact strings and wildcards (`*`). The implementation uses a cached regex engine (`xregexp.MatchString`) to evaluate patterns, allowing complex matching rules like `gpt-.*` to match any model starting with `gpt-`.

### What happens if I enable both `hideOriginalModels` and `hideMappedModels`?

These boolean flags in `ChannelSettings` control model list visibility for UI and CLI clients. If you enable both `hideOriginalModels` and `hideMappedModels`, the channel will effectively hide all model names from listings—both the client-side aliases (`from`) and the provider-native names (`to`). Typically, you should enable only one flag depending on whether you want users to see aliases or native model names.

### Is it possible to configure model mappings via environment variables or only through the API?

Based on the source code in [`internal/objects/channel.go`](https://github.com/looplj/axonhub/blob/main/internal/objects/channel.go) and the GraphQL schema in [`internal/server/gql/generated.go`](https://github.com/looplj/axonhub/blob/main/internal/server/gql/generated.go), model mappings are configured through the `ChannelSettings` struct or `APIKeyProfile` objects persisted in the database. While you can use the Go SDK (`biz.ChannelService.CreateChannel`) or the `axoncli` tool to import JSON/YAML configurations, the underlying storage mechanism is the database via these API interfaces rather than direct environment variable parsing.