For the complete documentation index, see llms.txt. Markdown versions of all docs pages are available by appending .md to any docs URL.
Configuration storage
Choose whether agentgateway stores UI-managed configuration in your config file, in a database, or not at all.
About
Agentgateway always reads a configuration file at startup. To control how configuration updates are persisted while agentgateway is running, such as when you use the UI or send a request to the config resource API, decide on your storage mode.
Note
This page covers the storage mode for agentgateway configuration only. For the config.database field, the choice between SQLite and PostgreSQL, and the other features that use the same database, see Database.
Storage modes
Set the mode in the config.storage.mode field of your configuration file. The mode values are file, hybrid, and readOnly, which are the literal values that the field accepts. 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:
storage:
mode: hybrid # file, hybrid, or readOnly
database:
url: sqlite:///config/data.db # required only in hybrid mode
gateways:
default:
port: 4000
ui:
gateways: defaultReview the following table to understand this configuration.
| Mode | What a write does | Requires a database |
|---|---|---|
file (default) | Agentgateway writes the resource into your configuration file, adding the section if the file does not have one yet. | No |
hybrid | Agentgateway keeps your configuration file as a read-only baseline and stores the resource in the database. At read time, it merges the stored resources over the baseline. | Yes |
readOnly | Agentgateway rejects the write with a 403 response and the message UI is configured as read-only. | No |
In hybrid mode, agentgateway never writes back to your configuration file. Instead, it stores the resource in the database that you configure in the UI or API, and layers it over the file value when it reads the configuration. Note that you can only update certain resources through the UI or API. For more information, see What the database stores.
Note
The Helm chart uses its own mode value with the names readonly and database, which the chart translates into the file and hybrid values of config.storage.mode. For more information, see Helm.
What the database stores
The database holds only the resource types in the following table. Everything else in the configuration file, such as the config section and the structure of the file itself, comes from your configuration file.
| Area | Resource types that the database can store |
|---|---|
| LLM | Providers, models, virtual models, API keys, and policies |
| MCP | Targets, policies, and settings |
| Traffic | Gateways, routes, and TCP routes |
| UI | Policies and the model catalog |
The overlay only adds resources. It does not replace a resource that your configuration file already defines. For example, in hybrid mode you can add a gateway in the UI, and agentgateway serves it alongside the gateways in your file. But if the resource that you store has the same name as one in your file, agentgateway rejects the write with a 409 response.
"config resource traffic.gateway/default conflicts with file-owned resource"To change a resource that your configuration file already defines, or to change a field that the database cannot hold, such as anything in the top-level config section, edit the configuration file that agentgateway reads at startup.
How each installation method differs
All three modes are available in all three installation methods, because the mode is a field in the same configuration file that every method reads. What differs is whether that file is writable, and how you set the mode.
| Method | Configuration file | Default behavior |
|---|---|---|
| Binary | A local file, writable. | file mode. UI edits are saved to your file. A generated configuration also sets a SQLite database for local runtime features, so hybrid mode needs no extra setup. |
| Docker | A mounted file or directory, writable unless you mount it read-only. | file mode. UI edits are saved to the file on your host. hybrid mode requires an additional database setup. |
| Helm | A ConfigMap that the chart renders from your values and mounts read-only. | The chart sets file mode, and because the mount is read-only, a UI save fails. Set the chart’s mode value to database to switch to hybrid and store edits in PostgreSQL. |
In the binary and Docker installations, you set config.storage.mode in your file, so all three modes are available to you directly. In the Helm installation, the chart derives config.storage.mode from its own mode value and overwrites anything that you set for the field yourself, so the chart offers file and hybrid storage only.
Binary and Docker
With the binary and Docker installations, your configuration file is writable, so the default file mode works with no extra setup and the UI can save your changes.
file mode
Use file mode when you want the UI to save your changes into the same configuration file that you edit by hand. No configuration is needed for this mode, because file is the default. The following steps confirm the behavior and show what agentgateway writes.
Confirm the storage mode that the running instance uses.
curl -s http://localhost:15000/api/runtime | jq '.ui.configStoreMode'Example output:
"file"Add an MCP server. The UI and the config resource API write to the same place, so use whichever you prefer.
Open the UI in your browser.
In the navigation, click MCP. If your configuration file has no
mcpsection yet, the entry is Get started. Click it, then click Enable to have agentgateway add the section to your file. If the file already has anmcpsection, the entry is Servers instead and you can skip this step.On the MCP Servers page, click Add server.
Enter a Server name, such as
my-target, keep the Streamable HTTP transport, and enter the URL of your MCP server, such ashttp://example.com/mcp.

Click Save server. Agentgateway writes the server into your configuration file, reloads the file, and confirms with Configuration saved.


Review your configuration file. Agentgateway added the server, and created the
mcpsection because the file did not have one.# yaml-language-server: $schema=https://agentgateway.dev/schema/config gateways: default: port: 4000 ui: gateways: default mcp: targets: - name: my-target mcp: host: http://example.com/mcpNote
If you enabled MCP in the UI, the
mcpsection also has aportfield, because Enable writes the capability’s default port along with the emptytargetslist.
Agentgateway preserves the schema comment at the top of the file, and reloads the file after it writes to it.
Important
In this mode the UI is a writer of your configuration file, not only a reader. If you keep your configuration in version control, or if you generate it from another tool, use readOnly or hybrid mode so that a UI edit cannot overwrite it.
hybrid mode
Use hybrid mode when you want the configuration file to stay exactly as you wrote it, and UI edits to persist somewhere else. Agentgateway accepts a postgres:// or postgresql:// URL for PostgreSQL, and treats any other value as a SQLite database path.
Set the storage mode and a database URL in your configuration file. A generated configuration already has the
databasefield, which points at a SQLite file next to the configuration file. In that case, you add only thestoragefield.The example also adds an empty
mcpsection. Inhybridmode agentgateway treats your file as a read-only baseline, so the UI cannot add a section to it, only resources within a section that already exists. For more information, see Sections must exist in the file.# yaml-language-server: $schema=https://agentgateway.dev/schema/config config: storage: mode: hybrid database: url: sqlite:///config/data.db gateways: default: port: 4000 ui: gateways: default mcp: targets: []Restart agentgateway. The
configsection is applied at startup, so the new mode does not take effect until the process restarts. For more information, see Fields that require a restart.Stop the current process, such as with
ctrl+c, then start it again.agentgateway -f config.yamlConfirm the storage mode.
curl -s http://localhost:15000/api/runtime | jq '.ui.configStoreMode'Example output:
"hybrid"Add an MCP server. The UI and the config resource API write to the same place, so use whichever you prefer.
Open the UI in your browser.
In the navigation, click MCP > Servers, then click Add server.
Enter a Server name, such as
persisted-target, keep the Streamable HTTP transport, and enter the URL of your MCP server, such ashttp://example.com/mcp.

Click Save server. Agentgateway stores the server in the database, leaves your configuration file untouched, and confirms with Configuration saved.


Note
The navigation offers Servers only because your configuration file already has an
mcpsection. Without it, the entry is Get started, and clicking Enable fails withFile configuration is read-only in hybrid mode. For more information, see Sections must exist in the file.Confirm that your configuration file is unchanged. The
mcpsection is still the empty one that you wrote, because agentgateway stored the server in the database instead of adding it here. Infilemode, the same save would have appended the target to this list.cat config.yamlExample output:
# yaml-language-server: $schema=https://agentgateway.dev/schema/config config: storage: mode: hybrid database: url: sqlite:///config/data.db gateways: default: port: 4000 ui: gateways: default mcp: targets: []Confirm that the effective configuration includes the server anyway. Agentgateway merges the stored resource over the file.
curl -s http://localhost:15000/api/config/effective | jq -c '.mcp'Example output:
{"targets":[{"name":"persisted-target","mcp":{"host":"http://example.com/mcp"}}]}Restart agentgateway again, then confirm that the server is still stored.
curl -s http://localhost:15000/api/config/resources | jq '.resources[].id'Example output:
"persisted-target"
readOnly mode
Use readOnly mode when your configuration file is the only source of truth and you want the UI to have read access only.
Set the mode in your configuration file.
# yaml-language-server: $schema=https://agentgateway.dev/schema/config config: storage: mode: readOnly gateways: default: port: 4000 ui: gateways: defaultRestart agentgateway, then confirm the mode.
curl -s http://localhost:15000/api/runtime | jq '.ui.configStoreMode'Example output:
"readOnly"Confirm that a write is rejected.
curl -s -X PUT http://localhost:15000/api/config/resources/mcp.target \ -H 'Content-Type: application/json' \ -d '{"resources":[{"value":{"name":"rejected","mcp":{"host":"http://example.com/mcp"}}}]}' \ -w "\nHTTP %{http_code}\n"Example output:
"UI is configured as read-only" HTTP 403
The UI still shows the running configuration in this mode. Only writes are rejected.
Helm
With the Helm chart, the configuration file is a ConfigMap that the chart renders from your Helm values and mounts read-only at the /config path. The proxy reads that file at startup, and the Helm values remain the source of truth.
Read-only storage keeps the deployment reproducible, but it also means that the UI cannot save anything. A save returns the following error, because write access to the mounted ConfigMap is denied.
failed to write to file `/config/config.yaml`: Read-only file system (os error 30)To let the UI store configuration, connect a PostgreSQL instance to your agentgateway pod and switch the Helm chart to database mode. Agentgateway then treats the ConfigMap as a baseline and keeps UI-managed resources in the database. When you make updates to these resources in the UI, agentgateway merges the resources from the database with the baseline in the ConfigMap.
Chart modes
In a Helm installation, you do not set config.storage.mode yourself. Instead, you set the chart’s mode value, and the chart renders the equivalent agentgateway storage mode into the ConfigMap for you.
Chart mode | Equivalent storage mode | Configuration source | UI saves |
|---|---|---|---|
readonly (default) | file | The Helm values that you provide to configure agentgateway. The values are translated and stored in a ConfigMap that is mounted to the agentgateway pod. | Config is read-only. UI updates are rejected. |
database | hybrid | The ConfigMap as a baseline, with an overlay in PostgreSQL. | Updates to resources that are editable in the UI are stored in the database. |
Everything that you put in your Helm values is part of the baseline, including the fields that you can later edit in the UI. In database mode, agentgateway never writes back to the ConfigMap. Instead, it stores your UI edit in the database and layers it over the baseline value when it reads the configuration.
To choose a mode, set the chart’s mode value. Do not set the config.storage.mode or config.database.url fields in your Helm values, because the chart derives both fields from mode and overwrites anything that you set for them. The chart also rejects a mode value other than readonly or database.
Important
Even in database mode, you cannot save the configuration file as a whole in the UI’s configuration editor, because the mounted file itself remains read-only. Treat your Helm values as the source of truth for the file, and the UI as the way to manage the resources that are layered on top of it.
Sections must exist in the file
Adding a capability in the UI adds a section to the configuration file, and in hybrid mode agentgateway never writes that file. Although the database can store the resources within a section, the UI cannot add the section itself.
Without a pre-existing section in the config for MCPs, LLMs, or gateways, the UI navigation shows a Get started path, but clicking Enable fails with the following error, because enabling the capability requires adding the section to the file.
File configuration is read-only in hybrid mode. Copy the diff and update the configuration file directly.To allow the UI to configure sections in your configuration file, you must define these sections in your Helm values file, even if they are empty, as shown in the following example and in the following steps.
config:
mcp:
targets: []Note
This constraint comes from hybrid mode, not from the read-only mount, so it applies to a binary or Docker installation in hybrid mode as well. Only file mode lets the UI add a section, because only file mode writes to your configuration file.
Deploy PostgreSQL
For a production deployment, use a managed PostgreSQL instance or an operator that handles backups and failover. The following example deploys a single instance for testing.
Warning
This example stores the database on an emptyDir volume, so the data exists only for the lifetime of the PostgreSQL pod. If that pod restarts or is rescheduled, the configuration that you saved in the UI is lost, and agentgateway falls back to the ConfigMap baseline. For anything beyond testing, back the database with a PersistentVolumeClaim, or use a managed PostgreSQL instance.
Create a Secret for the database credentials. The following example creates the
agwuser with apasswordpassword.kubectl create secret generic agentgateway-postgres \ -n agentgateway-system \ --from-literal=POSTGRES_USER=agw \ --from-literal=POSTGRES_PASSWORD='password' \ --from-literal=POSTGRES_DB=agwDeploy PostgreSQL.
kubectl apply -n agentgateway-system -f - <<'EOF' apiVersion: apps/v1 kind: Deployment metadata: name: postgres spec: replicas: 1 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 volumeMounts: - name: data mountPath: /var/lib/postgresql/data volumes: - name: data emptyDir: {} --- apiVersion: v1 kind: Service metadata: name: postgres spec: selector: app: postgres ports: - port: 5432 targetPort: 5432 EOFVerify that PostgreSQL is running.
kubectl rollout status deploy/postgres -n agentgateway-system
Switch to database mode
Set the
modevalue todatabaseand provide the connection URL in your Helm values file. Agentgateway creates the schema that it needs on first startup, so no migration step is required. You can optionally presetllmandmcpsections so that you can edit in the UI later.Switch the release to database mode without changing which capabilities the UI can manage. Use this option when you manage the configuration file in Helm values and use the database only to persist the resources for the sections that you already define.
cat <<'EOF' > values.yaml mode: database database: postgres: url: postgres://agw:[email protected]:5432/agw EOFNote
The chart rejects a
database.postgres.urlvalue that does not begin withpostgres://orpostgresql://, and rejects the value entirely whenmodeisreadonly. The URL is rendered into the ConfigMap, so use a database user with only the privileges that agentgateway needs.Upgrade the release with your values file.
helm upgrade -i agentgateway-standalone \ oci://cr.agentgateway.dev/charts/agentgateway-standalone \ --namespace agentgateway-system \ --version 0.0.0-latest-dev \ --reuse-values \ -f values.yamlPort-forward the admin address.
kubectl port-forward -n agentgateway-system \ deploy/agentgateway-standalone 15000:15000Confirm that agentgateway now runs in hybrid storage mode.
curl -s http://localhost:15000/api/runtime | jq '.ui.configStoreMode'Example output:
"hybrid"
Add configuration in the UI
Now that storage is writable, add an MCP server. The UI and the config resource API write to the same place, so use whichever you prefer.
Note
The UI steps require the mcp section from the Storage settings and UI sections tab in the previous step. For more information, see Sections must exist in the file. The API steps work with either set of values, because the API creates the section for you when it stores the first MCP target.
Open the UI in your browser.
In the navigation, click MCP > Servers, then click Add server.
Enter a Server name, such as
persisted-target, keep the Streamable HTTP transport, and enter the URL of your MCP server, such ashttp://example.com/mcp.

Click Save server. Agentgateway confirms with Configuration saved and lists the server. The save succeeds only because storage is writable. In the default read-only mode, the same action fails.


Verify that configuration persists
Review the effective configuration. Agentgateway merges the database overlay over the ConfigMap baseline, so the server appears alongside the routes that you set in your Helm values.
curl -s http://localhost:15000/api/config/effective | jqExample output: Notice that your MCP server configuration is part of the merged config.
"mcp": { "targets": [ { "mcp": { "host": "http://example.com/mcp" }, "name": "persisted-target" } ] },Restart the agentgateway pod.
kubectl rollout restart deploy/agentgateway-standalone \ -n agentgateway-systemkubectl rollout status deploy/agentgateway-standalone \ -n agentgateway-systemPort-forward the admin address again, then confirm that the server is still available, even after the restart. You can also refresh MCP > Servers in the UI and see it still listed.
kubectl port-forward -n agentgateway-system \ deploy/agentgateway-standalone 15000:15000curl -s http://localhost:15000/api/config/resources | jq '.resources[].id'Example output:
"persisted-target"
Scale the deployment
Both storage modes support running more than one agentgateway proxy pod. In readonly mode, every agentgateway pod reads the same ConfigMap. In database mode, every agentgateway pod reads the same overlay from PostgreSQL, so a change that you make in the UI reaches all of them.
Add the
replicaCountvalue to the values file that you created earlier, and set it to the number of agentgateway pods that you want to run. Keep the rest of your values, because the upgrade command passes the whole file and a value that you leave out returns to its default, which would send the release back to read-only storage.replicaCount: 3 mode: database database: postgres: url: postgres://agw:[email protected]:5432/agw config: gateways: default: port: 4000 llm: providers: [] models: [] virtualModels: [] mcp: targets: [] routes: - matches: - path: pathPrefix: / backends: - host: httpbin.httpbin.svc.cluster.local:8000Upgrade the release with your values file.
helm upgrade -i agentgateway-standalone \ oci://cr.agentgateway.dev/charts/agentgateway-standalone \ --namespace agentgateway-system \ --version 0.0.0-latest-dev \ --reuse-values \ -f values.yamlVerify that the deployment scaled to three agentgateway pods.
kubectl get pods -n agentgateway-system \ -l app.kubernetes.io/name=agentgateway-standalone
Cleanup
You can remove the resources that you created in this guide.Remove the MCP target that you created.
curl -s -X DELETE http://localhost:15000/api/config/resources/mcp.target/persisted-targetRemove the
storagefield from your configuration file, and restart agentgateway to return to the defaultfilemode.