Skip to content
agentgateway has joined the Agentic AI Foundation — Learn more

For the complete documentation index, see llms.txt. Markdown versions of all docs pages are available by appending .md to any docs URL.

Database

Page as Markdown

Set up the SQLite or PostgreSQL database that the Analytics page, the Logs page, hybrid storage, and API key budgets need.

About

Agentgateway reads a configuration file at startup, and that file alone is enough for the proxy to route traffic. Some features need a database as well. The two hold different things. The configuration file describes how the proxy behaves. The database holds the data that these features accumulate while agentgateway runs, such as one record for each LLM request.

You set the database in the config.database field of your configuration file. Because the field is in the config section, agentgateway applies it at startup only, so a change to it takes effect after a restart.

# yaml-language-server: $schema=https://agentgateway.dev/schema/config
config:
  database:
    url: sqlite://./data.db
gateways:
  default:
    port: 4000
ui:
  gateways: default

Features that need a database

The proxy can route traffic with no database, so traffic use cases work by default.

The following features do not work without a database. When you set up a database, the features also share that database.

FeatureDescriptionWhat happens without a database
LLM analytics and logsThe UI shows Analytics and Logs for LLM requests (not other proxy traffic such as HTTP routes to a backend service). The Analytics page is also the cost dashboard. To show spend in dollars instead of tokens and calls, add a model cost catalog as well as a database. For the controls on the page, see Cost dashboard.Agentgateway starts, but each UI page reports request log database is not configured and the admin API returns a 500 response.
hybrid configuration storageWhen enabled, hybrid mode stores UI edit to agentgateway configuration in the database.Agentgateway does not start: config.storage.mode=hybrid requires config.database.url.
LLM API key budgetsAPI key budgets let you track LLM spend across restartsAgentgateway does not start: API key budgets require config.database to be configured.

Access logging database

Optionally, to keep request logs in a different database from the rest, you can set the config.logging.database field. Then, agentgateway writes request logs to the database in config.logging.database, and uses config.database for the other features.

For more information, see Store logs in a database.

Important

The config.logging.database field covers request logs only. It does not satisfy hybrid storage or API key budgets, because both features use the primary database. If you configure either feature with config.logging.database alone, agentgateway fails to start with the error in the preceding table.

Choose a database backend

Agentgateway selects the backend from the URL. A URL that starts with postgres:// or postgresql:// is PostgreSQL. Every other value is a SQLite database file.

BackendExample URLUse it when
SQLitesqlite://./data.dbYou run a single agentgateway instance and want no external service.
PostgreSQLpostgres://user:password@host:5432/dbnameYou run more than one replica, or you want the data to outlive the instance.

SQLite writes to a file, so agentgateway needs a writable directory for it. PostgreSQL needs a reachable server and a user that can create tables.

Warning

Do not point more than one agentgateway instance at the same SQLite file. Give each instance its own file instead, or use PostgreSQL. With one file for each instance, the Analytics page shows the traffic of the instance that you are connected to, not the traffic of the whole deployment.

Before you begin

Install agentgateway as a binary, a Docker container, or a Kubernetes Deployment with Helm.

Binary and Docker

In the binary and Docker installations, agentgateway writes the SQLite file to a directory that you control, so SQLite needs no extra service.

Use the generated database

When you start agentgateway with no configuration file, the generated configuration already sets a SQLite database, so no extra step is needed. The binary writes both files to your user config directory. A container writes both to the directory that you mount at the /config path.

  1. Start agentgateway with no configuration file.

    agentgateway
  2. Review the generated configuration. The config.database.url field points at a SQLite file next to the configuration file. The following example is the file that a container generates. The binary generates the same file, with the absolute path of your user config directory in the URL.

    # yaml-language-server: $schema=https://agentgateway.dev/schema/config
    config:
      database:
        url: sqlite:///config/data.db
    gateways:
      default:
        port: 4000
    ui:
      gateways: default

Because the generated configuration attaches the UI to the default gateway, the Analytics page is served on the gateway port, such as http://localhost:4000/ui/llm/analytics. The generated configuration has no llm section yet, so the LLM section of the navigation appears only after you add a model.

Add a database to your own configuration file

A configuration file that you write yourself has no database until you add one. Add the config.database field, then restart agentgateway.

  1. Add the config.database.url field to your configuration file.

    The path is relative to the directory that you start agentgateway from.

    # yaml-language-server: $schema=https://agentgateway.dev/schema/config
    config:
      database:
        url: sqlite://./data.db
    gateways:
      default:
        port: 4000
    ui:
      gateways: default
    llm:
      models:
      - name: gpt-4o-mini
        provider: openAI
        params:
          model: gpt-4o-mini
          apiKey: "$OPENAI_API_KEY"
  2. Restart agentgateway with the updated file.

    Stop the current process, such as with ctrl+c, then start it again.

    agentgateway -f config.yaml

Important

If agentgateway cannot create the SQLite file, the process exits with failed to initialize request log database. In a container, this error usually means that the directory in the URL is not mounted, or that the mount is read-only. Point the URL at a directory that agentgateway can write to, and mount that directory into the container.

Helm

The Helm chart mounts your configuration as a read-only ConfigMap. The chart does not install a database. Without a database, the Analytics and Logs pages report request log database is not configured.

For a new installation, follow Set up a database in the Helm installation guide.

For an existing installation, choose one of the following options.

OptionStorage modeUse it when
SQLite on a volumeThe chart’s default readonly modeYou want the Analytics and Logs pages, and you keep your Helm values as the only source of configuration.
PostgreSQL in database modeThe chart’s database modeYou also want the UI to save configuration changes, or you run more than one replica.

Add SQLite on a volume

In the default readonly mode, the chart sets the storage mode and nothing else, so a config.database field in your Helm values reaches the rendered ConfigMap unchanged. SQLite needs a writable directory, and the proxy container runs with a read-only root filesystem, so mount a volume for the database file.

Note

The chart’s own config value says not to set config.storage or config.database yourself. That restriction applies to database mode, where the chart derives both fields from the mode and database.postgres.url values and overwrites what you set. In readonly mode, the chart sets config.storage only, so your config.database value is preserved.

  1. Create a values file that sets the database URL and mounts a volume for it.

    cat <<'EOF' > values.yaml
    mode: readonly
    config:
      config:
        database:
          url: sqlite:///data/data.db
      gateways:
        default:
          port: 4000
      llm:
        models: []
      mcp:
        targets: []
      ui: {}
    extraVolumes:
    - name: agw-data
      emptyDir: {}
    extraVolumeMounts:
    - name: agw-data
      mountPath: /data
    EOF
    Review the following table to understand this configuration.
    SettingDescription
    config.config.database.urlThe agentgateway config.database.url field. The outer config value is the whole configuration file, so the agentgateway config section is nested inside it.
    extraVolumes and extraVolumeMountsA writable directory for the SQLite file. The proxy container mounts the ConfigMap read-only and runs with a read-only root filesystem, so no other path accepts a write.

    Warning

    An emptyDir volume exists only for the lifetime of the pod. When the pod restarts, the request log data is lost. To keep the data, back the volume with a PersistentVolumeClaim, or use PostgreSQL instead.

  2. Upgrade the release with your values file.

    helm upgrade -i agentgateway-standalone \
      oci://cr.agentgateway.dev/charts/agentgateway-standalone \
      --namespace agentgateway-system \
      --version  \
      --reuse-values \
      -f values.yaml
  3. Confirm that the chart rendered the database into the ConfigMap.

    kubectl get configmap agentgateway-standalone-config \
      -n agentgateway-system -o jsonpath='{.data.config\.yaml}'

    Example output:

    config:
      database:
        url: sqlite:///data/data.db
      storage:
        mode: file
    gateways:
      default:
        port: 4000
    llm:
      models: []
    mcp:
      targets: []
    ui: {}

Note

This option gives the Analytics and Logs pages a database, but it does not make the UI writable. The ConfigMap stays read-only, so a UI save still fails. To make the UI writable, see Configuration storage.

Add PostgreSQL in database mode

The chart’s database mode sets both config.database.url and config.storage.mode: hybrid for you. One PostgreSQL instance then serves the request log, the configuration overlay, and API key budgets.

Deploy PostgreSQL in the namespace of your agentgateway release. For production, use a managed PostgreSQL service or an operator that handles backups and failover. The following steps deploy one PostgreSQL instance for testing.

  1. Create a Secret for the database credentials. PostgreSQL and the proxy use the same Secret, keeping the password out of your Helm values.

    This testing example creates the agw user with the password password. For a custom password, use only letters and numbers. The password becomes part of a connection URL, where characters such as @, :, and / have special meanings.

    kubectl create secret generic agentgateway-postgres \
      -n agentgateway-system \
      --from-literal=POSTGRES_USER=agw \
      --from-literal=POSTGRES_PASSWORD='password' \
      --from-literal=POSTGRES_DB=agw
  2. Deploy PostgreSQL with a PersistentVolumeClaim that uses your cluster’s default StorageClass. The volume preserves request logs and saved UI configuration when the PostgreSQL pod restarts.

    kubectl apply -n agentgateway-system -f - <<'EOF'
    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: postgres-data
    spec:
      accessModes:
      - ReadWriteOnce
      resources:
        requests:
          storage: 1Gi
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: postgres
    spec:
      replicas: 1
      strategy:
        type: Recreate
      selector:
        matchLabels:
          app: postgres
      template:
        metadata:
          labels:
            app: postgres
        spec:
          containers:
          - name: postgres
            image: postgres:16-alpine
            envFrom:
            - secretRef:
                name: agentgateway-postgres
            env:
            - name: PGDATA
              value: /var/lib/postgresql/data/pgdata
            ports:
            - containerPort: 5432
            readinessProbe:
              exec:
                command: ["sh", "-c", "pg_isready -U \"$POSTGRES_USER\" -d \"$POSTGRES_DB\""]
              periodSeconds: 5
            volumeMounts:
            - name: data
              mountPath: /var/lib/postgresql/data
          volumes:
          - name: data
            persistentVolumeClaim:
              claimName: postgres-data
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: postgres
    spec:
      selector:
        app: postgres
      ports:
      - port: 5432
        targetPort: 5432
    EOF
  3. Verify that PostgreSQL is ready and its PersistentVolumeClaim is Bound. The pod becomes ready when PostgreSQL accepts connections.

    kubectl rollout status deploy/postgres -n agentgateway-system
    kubectl get pvc postgres-data -n agentgateway-system

    Example output:

    deployment "postgres" successfully rolled out
    NAME            STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
    postgres-data   Bound    pvc-32a0dca7-4ddd-458c-85a4-1b1b9d37140c   1Gi        RWO            standard       13s

    If the claim stays Pending, check whether your cluster has a default StorageClass. To select a StorageClass, set spec.storageClassName in the PersistentVolumeClaim. Alternatively, use a managed PostgreSQL service.

Then, switch the release to database mode.

  1. Create a values file with the mode, connection URL, and password environment variable.

    The extraEnv value loads POSTGRES_PASSWORD from the Secret. At startup, the proxy replaces ${POSTGRES_PASSWORD} in the URL with that environment variable’s value. The ConfigMap contains the reference instead of the password.

    cat <<'EOF' > values.yaml
    mode: database
    database:
      postgres:
        url: postgres://agw:${POSTGRES_PASSWORD}@postgres.agentgateway-system.svc.cluster.local:5432/agw
    extraEnv:
    - name: POSTGRES_PASSWORD
      valueFrom:
        secretKeyRef:
          name: agentgateway-postgres
          key: POSTGRES_PASSWORD
    config:
      gateways:
        default:
          port: 4000
      llm:
        models: []
      mcp:
        targets: []
      ui: {}
    EOF

    Note

    Do not set config.config.database in database mode. The chart derives the field from the mode and database.postgres.url values, and overwrites anything that you set for it yourself.

  2. Upgrade the release with your values file.

    helm upgrade -i agentgateway-standalone \
      oci://cr.agentgateway.dev/charts/agentgateway-standalone \
      --namespace agentgateway-system \
      --version  \
      --reuse-values \
      -f values.yaml
  3. Confirm that the tables exist. Agentgateway creates them on the first startup.

    kubectl exec -n agentgateway-system deploy/postgres \
      -- psql -U agw -d agw -c '\dt'

    Expect the following tables, including request_logs for LLM logs and agw_config_resources for UI configuration changes:

                           List of relations
     Schema |                 Name                 | Type  | Owner
    --------+--------------------------------------+-------+-------
     public | _agentgateway_request_log_migrations | table | agw
     public | agw_config_resources                 | table | agw
     public | budget_usage                         | table | agw
     public | request_log_payloads                 | table | agw
     public | request_logs                         | table | agw
    (5 rows)

Verify that agentgateway records requests

Agentgateway records LLM requests only, so send a request to an LLM model to confirm that the database works. These steps need at least one model in the llm section of your configuration. For the steps to add one, see the LLM quickstart.

  1. Make the gateway port and the admin address reachable from your machine.

    Both addresses are already local. The gateway listens on port 4000, and the admin address on port 15000.
  2. Send a request to an LLM model through agentgateway.

    curl -s http://localhost:4000/v1/chat/completions \
      -H "Content-Type: application/json" \
      -d '{
        "model": "gpt-4o-mini",
        "messages": [{"role": "user", "content": "Say hello in one sentence."}]
      }' | jq .
  3. Review the request log. The admin API is served in the same places as the UI, so use the admin address or the gateway port that serves the UI. For more information, see Launch the UI.

    curl -s -X POST http://localhost:15000/api/logs/search \
      -H 'Content-Type: application/json' -d '{}' | jq .

    Example output: Agentgateway records the model, the token counts, and the duration for each request.

    {
      "logs": [
        {
          "id": "01a03f23-f49e-7b31-90f8-0ba440d7c8fa",
          "startedAt": "2026-08-26T17:35:09.010434Z",
          "completedAt": "2026-08-26T17:35:16.123561Z",
          "durationMs": 7113,
          "httpStatus": 200,
          "genAi": {
            "operationName": "chat",
            "providerName": "openai",
            "requestModel": "gpt-4o-mini",
            "responseModel": "gpt-4o-mini-2024-07-18"
          },
          "usage": {"inputTokens": 14, "outputTokens": 5, "totalTokens": 19}
        }
      ],
      "nextCursor": null
    }
  4. Open the LLM > Analytics page in the UI, such as http://localhost:15000/ui/llm/analytics. The request appears in the chart and in the breakdown. For more information about the controls on the page, see Cost dashboard.

Next steps

Was this page helpful?
Agentgateway assistant

Ask me anything about agentgateway configuration, features, or usage.

Note: AI-generated content might contain errors; please verify and test all returned information.

Tip: one topic per conversation gives the best results. Use the + button in the chat header to start a new conversation.

Switching topics? Starting a new conversation improves accuracy.
↑↓ navigate ↵ select esc dismiss

What could be improved?

Your feedback helps us improve assistant answers and identify docs gaps we should fix.

Need more help? Join us on Discord: https://discord.gg/y9efgEmppm

Want to use your own agent? Add the Solo MCP server to query our docs directly. Get started here: https://search.solo.io/.