> ## Documentation Index
> Fetch the complete documentation index at: https://gomodel-feat-litellm-db-import.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Migrating from LiteLLM

> Convert a LiteLLM proxy config.yaml to GoModel with one command, run both gateways side by side, and move clients over without changing model names.

GoModel speaks the same OpenAI-compatible API as the LiteLLM proxy, so most
applications only need a new base URL and key. The work is in the gateway
config, and `gomodel migrate litellm` does most of it.

| What | How it moves |
| - | - |
| `model_list`, `router_settings`, `litellm_settings`, `general_settings` | Converted by `gomodel migrate litellm` |
| Model names clients call | Kept: every `model_name` becomes a [virtual model](/features/virtual-models) |
| Master key | Kept |
| Virtual keys, teams, users, organizations | Imported from the LiteLLM database; clients keep their `sk-...` keys ([below](#4-import-keys-teams-and-budgets)) |
| Model access, budgets, rate limits | Imported onto GoModel [user paths](/features/user-path) |
| Spend | Not carried over: budgets start from zero |

## 1. Convert the config

Run a dry run first. It prints the migration report and the generated config,
and writes nothing:

```bash theme={null}
gomodel migrate litellm litellm_config.yaml
```

Then write the files:

```bash theme={null}
gomodel migrate litellm --out ./gomodel litellm_config.yaml
```

With Docker (the image runs as a non-root user, so pass yours to write into the
mounted directory):

```bash theme={null}
docker run --rm --user "$(id -u):$(id -g)" -v "$PWD":/work \
  enterpilot/gomodel migrate litellm --out /work/gomodel /work/litellm_config.yaml
```

`--out` writes three files and refuses to overwrite them unless you pass
`--force`:

| File | Contents |
| - | - |
| `config.yaml` | Providers, virtual models, retries, timeouts, and observability settings |
| `.env` | Secrets that were inline in the LiteLLM config (API keys, master key). Created with mode `0600`; keep it out of version control |
| `MIGRATION_REPORT.md` | Providers and virtual models created, environment variables to set, and every setting changed or left behind |

`os.environ/NAME` references become `${NAME}`, so the environment you already
run LiteLLM with keeps working. `include:` files are followed.

## 2. Review the report

Read `MIGRATION_REPORT.md` before sending traffic. It has three lists:

* **Review before switching traffic**: things you must finish, such as
  guardrails, model access groups, or a Langfuse callback. GoModel guardrails
  are off until you configure them.
* **Not migrated**: settings with no GoModel equivalent, named one by one.
  Nothing is dropped silently.
* **Behavior changes**: settings that were converted but behave a little
  differently, such as routing strategies.

## 3. Run GoModel next to LiteLLM

Start GoModel with the generated files on another port. Add the variables
listed under **Environment** in the report (the ones LiteLLM already read with
`os.environ/`) to `.env`, creating it if the converter wrote none. GoModel
refuses to start while the variable `server.master_key` reads is unset. Then
send a few test requests with the models your clients use:

```yaml compose.yaml theme={null}
services:
  gomodel:
    image: enterpilot/gomodel
    ports: ["8080:8080"]
    env_file: .env
    volumes:
      - ./config.yaml:/app/config/config.yaml:ro
```

```bash theme={null}
cd gomodel
docker compose up
```

Load `.env` with Compose `env_file` (or GoModel's own `.env` loader when you
run the binary from that directory). `docker run --env-file` reads values
literally, so it would keep the quotes `.env` puts around values such as
inline JSON credentials. When you run the binary directly, a variable already
exported in your shell, such as `OPENAI_API_KEY`, wins over the same name in
`.env`.

```bash theme={null}
curl -s http://localhost:8080/v1/chat/completions \
  -H "Authorization: Bearer $LITELLM_MASTER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model": "gpt-4o", "messages": [{"role": "user", "content": "ok?"}]}'
```

`GET /v1/models` lists the same model names LiteLLM did. Then move clients
over one team at a time.

## 4. Import keys, teams, and budgets

LiteLLM keeps virtual keys, teams, users, organizations, and their budgets in
its PostgreSQL database. The same command reads them when it knows the
database: `--database-url`, else the config's `general_settings.database_url`,
else `DATABASE_URL`. It only reads, inside a read-only transaction. Without a
database URL it converts the config alone.

Once GoModel runs with the converted config, import into it:

```bash theme={null}
gomodel migrate litellm --database-url "$LITELLM_DATABASE_URL" \
  --gomodel-url http://localhost:8080 litellm_config.yaml
```

The command authenticates with `GOMODEL_MASTER_KEY`, else the LiteLLM master
key, and needs `https` for a GoModel on another machine (`--allow-http` on a
trusted network, such as a Compose network). Without `--gomodel-url` it only
lists the import in the report.

Run it again while both gateways run side by side: it brings GoModel up to date
with LiteLLM. Keys get their current path, labels, allowed models, and expiry,
and keys LiteLLM has since blocked or expired are deactivated. Dashboard access
granted and keys deactivated in GoModel stay as they are. Rules for a path are
written before its keys; if one is rejected, those keys are held back and the
command exits with an error.

Each key keeps its `sk-...` value: LiteLLM stores only a SHA-256 hash of it,
and GoModel [imports that hash](/advanced/admin-endpoints#importing-keys-from-litellm),
so GoModel never handles the key itself. Everything else lands on a
[user path](/features/user-path):

| LiteLLM | GoModel user path |
| - | - |
| Organization | `/<organization>` |
| Team | `/<organization>/<team>`, or `/<team>` without one |
| Team key | `/<organization>/<team>/<key alias>` |
| Personal key | `/users/<user>/<key alias>` |
| Key with no team or user | `/keys/<key alias>` |

| LiteLLM setting | GoModel |
| - | - |
| `models` on an organization, team, or user | [Allowed models](/features/users) on its path |
| `models` on a key | The key's allowed models |
| `max_budget` + `budget_duration` | [Budget](/features/budgets) on the path |
| `rpm_limit` / `tpm_limit`, `tpd_limit`, `max_parallel_requests` | [Rate limits](/features/rate-limits) per minute, per day, and concurrent |
| Key and team `metadata.tags` | Key [labels](/features/labelling) |
| `expires` | Key expiry |

Model access follows LiteLLM's rules. A user's model list binds that user's
personal keys, not the team keys they hold, because only personal keys sit
under `/users/<user>`. Model names resolve to the provider models behind them,
because GoModel checks the model a virtual model resolves to; if you later
point a virtual model at other models, update the allowed models that named it.

`budget_duration` maps to `hourly`, `daily`, `weekly`, or `monthly` (`30d` and
`1mo` both become `monthly`, which resets on calendar months), and other
durations to a fixed window. Not imported, and listed in the report:

* blocked or expired keys, and keys of blocked teams (deactivated if an
  earlier run imported them);
* budgets without `budget_duration`: GoModel budgets reset every period;
* spend: budgets start from zero, and the report shows LiteLLM's current spend
  next to each one;
* team member budgets and per-model budgets and limits.

## What changes for clients

| LiteLLM | GoModel |
| - | - |
| Base URL `http://litellm:4000` or `http://litellm:4000/v1` | Base URL must end in `/v1`: `http://gomodel:8080/v1` |
| Virtual key `sk-...` | Unchanged once [imported](#4-import-keys-teams-and-budgets); new keys are `sk_gom_...` |
| `model_name` aliases | Unchanged |
| `/health/liveliness`, `/health/readiness` | [`/health` and `/health/ready`](/advanced/cli#health-probe) |
| Pass-through `/anthropic/*`, `/gemini/*`, `/vertex_ai/*` | [`/p/{provider}/*`](/features/passthrough-api); Anthropic SDKs can also use `/v1/messages` directly |
| `metadata.tags` in the request body | A tagging header, such as `X-My-Tags`; see [Labelling](/features/labelling) |
| `x-litellm-*` response headers, `/key/*`, `/team/*` management API | GoModel's [admin API](/advanced/admin-endpoints) and [usage API](/advanced/usage-api) |

## How settings map

| LiteLLM | GoModel |
| - | - |
| `litellm_params.model: provider/model` | A provider in `providers`, and the model in its `models` list |
| Deployments sharing a `model_name` | A `round_robin` virtual model, weighted by `weight`, else `rpm`, else `tpm` |
| `routing_strategy: cost-based-routing` | Virtual model `strategy: cost` |
| Other routing strategies | `round_robin` with failover (noted in the report) |
| `fallbacks`, `default_fallbacks` | A `failover` virtual model that tries the group, then its fallbacks |
| `context_window_fallbacks`, `content_policy_fallbacks` | Not converted; add error phrases to [`failover.retry_on_errors`](/features/failover) |
| `model_group_alias` | A virtual model pointing at the group |
| `openai/*` wildcards | The provider serves its whole catalog; partial wildcards become a [`model_filter`](/advanced/config-yaml#filtering-a-providers-models) |
| `input_cost_per_token`, `output_cost_per_token`, `max_input_tokens` | Model `metadata.pricing` (per million tokens) and `context_window` |
| Deployment `rpm` / `tpm` under usage-based routing | [Model rate limits](/features/rate-limits) |
| `num_retries`, `timeout` | `resilience.retry.max_retries`, `http.timeout` |
| `allowed_fails`, `cooldown_time` | Circuit breaker `failure_threshold`, `timeout` |
| `callbacks: prometheus` / `otel` | `metrics.enabled` / `opentelemetry.enabled` |
| `callbacks: langfuse` | [Langfuse over OpenTelemetry](/guides/langfuse) |
| `master_key` | `GOMODEL_MASTER_KEY` (or `server.master_key`) |
| `database_url` | Read for the import; GoModel uses its own [storage](/guides/production) |

Provider names follow GoModel's environment conventions: a deployment using
LiteLLM's default key variable (`OPENAI_API_KEY`) becomes provider `openai`,
one reading `OPENAI_EU_API_KEY` becomes `openai-eu`, and each Azure deployment
becomes its own provider, such as `azure-gpt-4o-prod`.

Providers GoModel does not support yet, such as Replicate or SageMaker, are
listed under **Not migrated** in the report.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.