How DIAL Core is configured
DIAL Core takes two kinds of configuration: static settings that shape the running server, and dynamic configuration that defines what it serves. This page explains where each one lives, how Core merges and reloads dynamic configuration, and which page documents each entity. It is for platform engineers who configure Core; it assumes you have read the DIAL Core overview.
Static settings and dynamic configuration
| Static settings | Dynamic configuration | |
|---|---|---|
| What it controls | The server, outbound clients, storage, Redis, identity providers, encryption, and other runtime behavior | Models, applications, interceptors, routes, toolsets, roles, keys, translators, schemas, and global settings |
| Where it lives | A JSON file named by AIDIAL_SETTINGS, environment variables with the aidial. prefix, and the defaults bundled with Core | JSON config files listed in config.files, and entities stored in the platform bucket of blob storage |
| When a change applies | At the next restart | While Core runs: on the next reload for files, on return for a Configuration API write |
| Reference | Static settings | The entity pages listed below |
File location
Static settings come from the file named by the AIDIAL_SETTINGS environment variable. Config files are listed in the static setting config.files; Core has no config file by default ([]). This Docker Compose fragment mounts both:
core:
environment:
AIDIAL_SETTINGS: /opt/settings/settings.json
aidial.config.files: '["/opt/config/config.json"]'
volumes:
- ./settings:/opt/settings
- ./core:/opt/config
Where dynamic configuration is stored
Core builds the dynamic configuration it serves from two sources:
- Config files. Core deep-merges the JSON files listed in
config.files, in order; a later file overrides keys from an earlier one. Arrays are concatenated unlessconfig.jsonMergeStrategy.overwriteArraysistrue. A path that is not found on disk is read from the classpath. - The
platformbucket. Entities written through the Configuration API are stored as blobs in Core's blob storage, one blob per entity, under a canonical ID<type>/platform/<name>— for examplemodels/platform/gpt-4o. Secret fields are encrypted before they are stored.
The Configuration API is in preview. Config files remain fully supported, and you can use either source or both.
How the two sources are merged
Core serves the union of the config files and the platform bucket:
- A blob replaces the file entity with the same name, as a whole. This applies to models, interceptors, translators, roles, applications, and toolsets; schemas are matched by
$id. No field of the file entity survives. - Keys and routes are never shadowed. A key is matched by its secret and a route by its paths, so a file entry and a blob entry of the same name both stay in force.
- Global settings are an overlay. When the blob
settings/platform/globalexists, Core takesglobalInterceptors,retriableErrorCodes,rateLimitSchedule, andspendingLimitsfrom it instead of from the files. Deleting the blob restores the file values. See Global settings. - Public resources stay out. Applications and toolsets in the
publicbucket are not part of the merged configuration.
Secrets at rest
Core never stores a secret in a blob as plain text:
- The
keyof an API key, and thekeyandsecretExtraDataof an upstream or interface, are stored asENC[...]. - The
auth_settings.client_secretandcode_verifierof applications and toolsets are stored as base64 ciphertext.
No Configuration API read returns a secret. For applications and toolsets, an admin gets a client_secret_hint instead of the secret. Secrets in config files are read as written, so keep those files in a secret store.
Reload and consistency
- Config files are re-read every
config.reloadmilliseconds (default60000), and the merged configuration is rebuilt from the files and the blobs. If a re-read fails to open, parse, or validate a file, Core keeps the last good configuration and logs a warning. - Configuration API writes apply on the instance that served them before it answers, so the next request to that instance sees the change. Other instances apply it when they receive the resource event, and every instance converges on its next full rebuild.
- On demand, an admin can send
POST /v1/ops/config/reloadto re-read the files and rebuild the configuration synchronously. The answer is the merged configuration as JSON.
Invalid entities
config.onInvalidEntity decides what a semantic violation does to a rebuild, such as a duplicate deployment ID:
abort(default) fails the rebuild and keeps the previous configuration. At startup, Core does not start.skipdrops the offending entity alone and records it as invalid.
A blob that cannot be parsed or decrypted is always skipped and recorded, whatever the mode. GET /v1/admin/health/config reports degraded and lists each skipped entity while any is recorded. The setting is described in Config loading.
Dynamic configuration entities
Each entity type has the same fields in a config file and in the platform bucket. Deployment IDs are shared: a model, an application, a toolset, and an interceptor cannot have the same name.
| Entity | What it is | Config file key | Configuration API path | Reference |
|---|---|---|---|---|
| Model | An LLM or embedding model served through Core | models | /v1/models/platform/{name} | Models |
| Upstream | One provider endpoint behind a model or route, for load balancing | models.<name>.upstreams | — | Load balancing and upstreams |
| Translator | A service that converts one AI API into another | translators | /v1/translators/platform/{name} | Translators |
| Application | An agent or app served through Core | applications | /v1/applications/platform/{name} | Applications |
| Application type schema | A JSON schema that defines a type of schema-rich application | applicationTypeSchemas | /v1/schemas/platform/{name} | Application type schemas |
| Interceptor | A service that processes requests and responses | interceptors | /v1/interceptors/platform/{name} | Interceptors |
| Route | A custom HTTP or WebSocket API proxied through Core | routes | /v1/routes/platform/{name} | Routes |
| Toolset | An MCP server registered in Core | toolsets | /v1/toolsets/platform/{name} | Toolsets |
| Role | Limits and sharing rules for a group of callers | roles | /v1/roles/platform/{name} | Roles |
| Key | An API key, its project, and its roles | keys | /v1/keys/platform/{name} | Keys |
| Global settings | Deployment-wide interceptors, retriable errors, limit schedule, and spending limits | globalInterceptors, retriableErrorCodes, rateLimitSchedule, spendingLimits | /v1/settings/platform/global | Global settings |
| Catalog schema | A schema for the metadata a deployment shows in the Catalog | catalogSchemas | /v1/catalog_schemas/platform/{name} | Catalog schemas |
The Configuration API also stores budget policies and policy assignments (/v1/policies/platform/... and /v1/policy_assignments/platform/...), which config files cannot hold. The Core documentation does not describe their fields yet. Org unit roles (orgUnitRoles) belong to org units, a preview feature off by default.
The Static settings and gflog.xml pages cover the startup configuration.
Working examples
Complete configuration files are in the AI DIAL repository:
| Setup | Files |
|---|---|
| Echo application | dial-docker-compose/application/ |
| Azure models | dial-docker-compose/model/ |
| Ollama (self-hosted) | dial-docker-compose/ollama/ |
| Production (Keycloak, DIAL Admin) | dial-docker-compose-advanced/dial-2.x/ |