> ## Documentation Index
> Fetch the complete documentation index at: https://gomodel.enterpilot.io/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Updating GoModel

> Update GoModel on Docker or the standalone binary, back up your database first, and understand what the automatic schema migrations do.

Updating GoModel is a pull and a restart. Schema migrations are built into the
binary and run automatically on the first start of the new version, so there is
no separate migration step and no maintenance window beyond the restart.

<Warning>
  **Back up your database before every update.** GoModel is under active
  development and ships often, and some upgrades transform stored data. A copy
  is the only thing that makes a bad upgrade a five-minute problem instead of a
  lost audit trail, usage history, and set of managed API keys.
</Warning>

## 1. Back up the database

<Tabs>
  <Tab title="SQLite (Docker volume)">
    Stop the gateway so the file is not written mid-copy, then archive the
    volume:

    ```bash theme={null}
    docker compose stop gomodel
    docker run --rm \
      -v gomodel_data:/data -v "$PWD":/backup alpine \
      tar czf /backup/gomodel-$(date +%F).tar.gz -C /data .
    ```

    Replace `gomodel_data` with your volume name (`docker volume ls`). If you
    bind-mount a host directory instead, `cp -a ./data ./data.bak-$(date +%F)`
    is enough.
  </Tab>

  <Tab title="SQLite (binary)">
    Stop the gateway, then copy the database file printed at startup as
    `storage configured`:

    ```bash theme={null}
    cp -a ~/.local/share/gomodel/gomodel.db gomodel-$(date +%F).db   # Linux
    ```

    On macOS the default is
    `~/Library/Application Support/gomodel/gomodel.db`. See
    [where GoModel stores its data](/docs/about/faq#where-does-gomodel-store-its-data).
  </Tab>

  <Tab title="PostgreSQL">
    ```bash theme={null}
    pg_dump "$POSTGRES_URL" > gomodel-$(date +%F).sql
    ```
  </Tab>

  <Tab title="MongoDB">
    ```bash theme={null}
    mongodump --uri="$MONGODB_URL" --out "gomodel-$(date +%F)"
    ```
  </Tab>
</Tabs>

## 2. Update

### Docker Compose

```bash theme={null}
docker compose pull gomodel
docker compose up -d gomodel
docker compose logs -f gomodel
```

The logs should show the new version on the first line and a
`storage configured` line with your database path.

<Warning>
  **Check that your database is on a volume before you update.** The image
  declares none, so a container without a mount at `/app/data` keeps its SQLite
  database in the container's own filesystem — and loses everything the moment
  the container is replaced by the update. See
  [production storage](/docs/guides/production#choose-a-storage-backend).
</Warning>

### docker run

Recreating the container discards its flags, so read them off the running one
first:

```bash theme={null}
docker inspect gomodel --format '{{json .Mounts}} {{.Config.Env}}'
```

If nothing is mounted at `/app/data`, the database lives in the container
filesystem and `docker rm` deletes it. Copy it out and seed the volume you are
about to mount, while the old container still exists — an empty volume hides the
copy, and the gateway starts with no keys, usage, or logs:

```bash theme={null}
docker cp gomodel:/app/data/. ./gomodel-data
docker run --rm -v gomodel_data:/data -v "$PWD/gomodel-data":/seed alpine \
  sh -c 'cp -a /seed/. /data/ && chown -R 65532:65532 /data'
```

`65532` is the image's nonroot UID — the gateway cannot write a volume owned by
anyone else.

Then replace the container, passing the same mount and environment flags back:

```bash theme={null}
docker pull enterpilot/gomodel
docker rm -f gomodel
docker run -d --name gomodel -p 8080:8080 \
  -v gomodel_data:/app/data \
  --env-file .env \
  enterpilot/gomodel
```

### Binary

Re-run the installer. It fetches the latest release and replaces the binary in
place:

<Tabs>
  <Tab title="macOS / Linux">
    ```bash theme={null}
    curl -fsSL https://gomodel.enterpilot.io/install.sh | sh
    ```
  </Tab>

  <Tab title="Windows">
    ```powershell theme={null}
    irm https://gomodel.enterpilot.io/install.ps1 | iex
    ```
  </Tab>
</Tabs>

Restart the gateway afterwards — there is no in-place hot upgrade.

## 3. Verify

```bash theme={null}
gomodel --version
curl -s http://localhost:8080/version
```

`GET /version` reports the running version, the latest published release, and
whether an update is available:

```json theme={null}
{
  "app": "GoModel",
  "version": "0.1.60",
  "latest": "0.1.60",
  "update_available": false,
  "enabled": true
}
```

The dashboard's **Settings** page shows the same result. See
[Version Awareness](/docs/advanced/version-awareness) for how that check works and
how to disable it.

## What migrations do

Migrations run on the first start of a new version. There is no separate
migration command, and an update never moves or deletes your database,
configuration, or cache.

Most are additive: missing tables, indexes, and columns are created, and a
partially applied schema is safe to retry on the next start. Some releases
transform storage instead — when budgets and rate limits gained scopes, their
tables were rebuilt and the old ones dropped. Both are safe going forward, which
is what makes the reverse direction worth care.

## Pinning a version

Updates default to the latest release. To stay on a known version, pin it:

<Tabs>
  <Tab title="Docker">
    ```bash theme={null}
    docker pull enterpilot/gomodel:X.Y.Z
    ```

    Use the version tag in your compose file instead of `latest`.
  </Tab>

  <Tab title="macOS / Linux">
    ```bash theme={null}
    curl -fsSL https://gomodel.enterpilot.io/install.sh | GOMODEL_VERSION=vX.Y.Z sh
    ```
  </Tab>

  <Tab title="Windows">
    ```powershell theme={null}
    $env:GOMODEL_VERSION = "vX.Y.Z"
    irm https://gomodel.enterpilot.io/install.ps1 | iex
    ```
  </Tab>
</Tabs>

Replace `X.Y.Z` with a
[published release](https://github.com/ENTERPILOT/GoModel/releases).

## Rolling back

Install or pull the previous version and restart. That is enough only if every
migration in between was additive; across a transforming one the older binary
looks for storage the upgrade rebuilt. You cannot tell the two apart from the
outside, so **restore the step 1 backup** unless the older version is known to
start against the migrated database.

Restoring a SQLite volume backup replaces the volume's contents, so stop the
gateway first — `docker compose stop gomodel`, or `docker stop gomodel` for a
standalone container — then unpack the archive and start it again:

```bash theme={null}
docker run --rm -v gomodel_data:/data -v "$PWD":/backup alpine \
  sh -c 'rm -rf /data/* && tar xzf /backup/gomodel-YYYY-MM-DD.tar.gz -C /data \
         && chown -R 65532:65532 /data'
```

## If something goes wrong

| Symptom                                                         | Cause                                                                                                                               |
| --------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| Dashboard is empty after the update: no keys, no usage, no logs | The database was not on a volume, or `SQLITE_PATH` resolved somewhere else. Compare the `storage configured` path before and after. |
| Gateway will not start after the update                         | Read the first error line. Configuration that was previously ignored can become validated; the release notes list breaking changes. |
| The version did not change                                      | The old container is still running (`docker ps`), or a second `gomodel` binary earlier in `PATH` is being launched.                 |

Still stuck? Ask on [Discord](https://discord.gg/gaEB9BQSPH) or open a
[GitHub issue](https://github.com/ENTERPILOT/GoModel/issues).
