Configuration reference
Reference · Configuration
askdb.config.ts holds every setting the CLI, Studio, the HTTP API and createAskDb() read. Environment variables reach it through env() calls in the file. This page lists each key. To load the config in your own code, see the @askdb/config API.
askdb.config.ts
Section titled “askdb.config.ts”askdb init scaffolds this file. It uses defineConfig for type safety:
import { defineConfig, env } from "@askdb/config";
export default defineConfig({ ai: { provider: "openai", providerConfig: { openai: { apiKey: env("OPENAI_API_KEY") }, }, language: { model: env("OPENAI_MODEL") }, embedding: { model: "text-embedding-3-small" }, }, introspection: { provider: "postgres", providerConfig: { postgres: { databaseUrl: env("DATABASE_URL") }, }, outputDir: "./my-app.schema", }, rag: { embedder: "ai", store: "pgvector", storeConfig: { pgvector: { databaseUrl: env("PGVECTOR_URL") }, }, }, logging: { level: "info", },});env(name) and requiredEnv(name), both from @askdb/config, read an environment variable when the config file loads, and trim it:
env()returnsundefinedwhen the variable is missing or blank, so the field stays unset and gets its default.requiredEnv()throws when the variable is missing or blank. Every command loads the whole config, so the variable must be set even for a command that doesn’t use it, such as an API key when you runaskdb introspect.
defineConfig types the object as AskDbConfig, so your editor checks it as you write. A plain export default { … } loads too: AskDB runs it through defineConfig when it loads the file, so both forms get the same checks.
All top-level fields
Section titled “All top-level fields”| Field | Required | What it configures |
|---|---|---|
ai | yes | Provider connections (provider, providerConfig), the language model (language) and the embedding model (embedding). See The ai block and Bring your own model. |
introspection | yes | The engine askdb introspect reads (provider), its connection (providerConfig), the output directory (outputDir) and the schemas to read (schemas). See The introspection block. |
dialect | no | Overrides the NL-to-SQL dialect: postgres, cockroachdb, mysql, mariadb, sqlite or sqlserver. When unset, it’s inferred from the schema artifact’s recorded provider. See dialect. |
rag | no | Experimental. The embedder (mock, or ai for the ai.embedding model), the vector store (file, memory, pgvector) and the store’s options. Omit it when you don’t use retrieval: AskDB then uses the mock embedder and the in-memory store. See The rag block. |
modes | no | askdbMode (schema_only default, bounded_results) and omitSensitiveFromPrompt (default false). Both are floors: a CLI flag, a client call, or an HTTP request can tighten them, never loosen them. See modes and host. |
host | no | schemaPath or schemaJson: the default schema artifact for createAskDb and the HTTP API. See modes and host. |
logging | no | The level, log file and stdout copy of the structured logs from the CLI and the HTTP API server, and the CLI’s correlation ID. See logging and dev. |
dev | no | mockSql: fixed SQL in place of the model call, for tests. See logging and dev. |
studio | no | Experimental. Studio’s listen address and the Query Playground’s execute block. See The studio block. |
httpApi | no | The HTTP API server’s listen address, schema override and request timeout. See The httpApi block. |
A config without ai or introspection fails to load, with an error that names the file and the missing block. That includes a config you only use for askdb introspect: it still needs an ai block.
The sections below list every field of each block, with its type and default. Required in the Default column means the field must be set whenever its block is present, or under the condition the column names; every other field is optional. A config that sets a field AskDB no longer has fails to load (see Removed keys).
AskDB checks each field’s type when the config loads. A value of another type fails to load, with an error that names the file and the field, such as AskDB config at /app/askdb.config.ts: modes.omitSensitiveFromPrompt must be a boolean (got "false"). A boolean field takes only true or false, because the string "false" is truthy. A number field also takes a string that holds the number, such as "8080", since env() returns a string. A field set to undefined, as an unset env() read gives, takes its default, and so does a string field set to null.
The ai block
Section titled “The ai block”ai separates how to reach a provider from which model to use for what: providerConfig holds the connections, and language and embedding each pick a model.
| Field | Type | Default | Notes |
|---|---|---|---|
provider | string | none | The default provider for both sections: openai, azure, foundry, anthropic, google, gateway, or a custom provider id. |
providerConfig | object | none | Provider connections, keyed by provider id: keys, endpoints, Azure resources, API versions. No model names. See ai.providerConfig. |
language | object | ai.provider and its default model | The language model AskDB writes SQL and enrichment suggestions with. See ai.language. |
embedding | object | none | The embedding model behind rag.embedder: "ai". See ai.embedding. |
A section’s provider is its own provider, else ai.provider. Its connection is its own connection, else the connection named "default" within that provider. Loading fails when a section has no provider, names a connection that doesn’t exist, or uses a built-in provider with no connection at all. Each section only ever receives its own connection’s settings, so a key configured for one provider is never sent to another.
Anthropic for SQL, OpenAI for embeddings:
export default defineConfig({ ai: { provider: "anthropic", providerConfig: { anthropic: { apiKey: env("ANTHROPIC_API_KEY") }, openai: { apiKey: env("OPENAI_API_KEY") }, }, language: { model: "claude-sonnet-4-6" }, embedding: { provider: "openai", model: "text-embedding-3-small" }, }, rag: { embedder: "ai", store: "file", storeConfig: { file: {} } }, // ...});Two Azure resources, one for each model:
export default defineConfig({ ai: { provider: "azure", providerConfig: { azure: [ { resourceName: "eastus-chat", apiKey: env("AZURE_CHAT_KEY") }, // name: "default" { name: "westus", resourceName: "westus-embed", apiKey: env("AZURE_EMBED_KEY") }, ], }, language: { model: "my-gpt-4o-deployment", modelFamily: "gpt-4o" }, embedding: { connection: "westus", model: "my-embedding-deployment", dimensions: 1536 }, }, rag: { embedder: "ai", store: "pgvector", storeConfig: { pgvector: { databaseUrl: env("PGVECTOR_URL") } } }, // ...});ai.providerConfig
Section titled “ai.providerConfig”Keyed by provider id. Each value is one connection, or a list of connections when a provider needs more than one. Every connection field is a string with no default.
| Provider key | Connection fields |
|---|---|
openai | apiKey, baseUrl (any OpenAI-compatible endpoint) |
azure, foundry | apiKey, secondaryApiKey, resourceName (the subdomain of https://<name>.openai.azure.com), baseUrl (a full endpoint URL; overrides resourceName), apiVersion. One of resourceName or baseUrl is required. |
anthropic | apiKey, baseUrl |
google | apiKey, baseUrl |
gateway | apiKey, baseUrl (Vercel AI Gateway) |
| any other id | apiKey, baseUrl, for a custom provider |
Every connection also takes name, which defaults to "default" and must be unique within its provider. A list needs a "default" entry unless every section that uses the provider sets connection.
A baseUrl can’t hold a username or password: a config that sets one on any connection, used or not, fails to load, with an error that names the key and doesn’t repeat the URL. fetch refuses such a URL anyway. The same goes for OPENAI_BASE_URL and ANTHROPIC_BASE_URL in the environment, which the OpenAI and Anthropic SDKs read when the connection sets no baseUrl. Put the key in apiKey. To send other credentials, such as a proxy’s, build the model in your own code with the AI SDK provider’s headers option and pass it to ask() as model (see Bring your own model). The askdb CLI, Studio and the HTTP server can’t send extra headers.
ai.language
Section titled “ai.language”| Field | Type | Default | Notes |
|---|---|---|---|
provider | string | ai.provider | |
connection | string | "default" | A connection name in ai.providerConfig.<provider>. |
model | string | The provider’s default language model | openai: gpt-4o-mini. anthropic: claude-sonnet-4-6. google: gemini-2.0-flash. gateway: openai/gpt-4o-mini; an id without its <upstream>/ prefix is rejected when the model is built. azure and foundry: the deployment name, default gpt-4o-mini. A custom provider has no default. |
modelFamily | string | none | Azure and Foundry: the underlying model id when model is a deployment name. See Azure deployment names. |
reasoning | object | none | See Reasoning effort. |
ai.embedding
Section titled “ai.embedding”Read only when rag.embedder is "ai"; ignored for "mock". Setting it in a config with no rag block is an error.
| Field | Type | Default | Notes |
|---|---|---|---|
provider | string | ai.provider | Anthropic has no embeddings API, so a config whose ai.embedding provider resolves to anthropic fails to load. Set provider (for example "openai") and give it a connection. |
connection | string | "default" | A connection name in ai.providerConfig.<provider>. |
model | string | Required with rag.embedder: "ai" | AskDB has no default embedding model. On Azure, the embedding deployment name. On the AI Gateway, an <upstream>/<model> id such as openai/text-embedding-3-small. |
dimensions | number or string | The model’s own width | A positive integer, or a string holding one: the vector size to request from the provider, for models that let you choose one (OpenAI’s text-embedding-3 models, Gemini’s; on the AI Gateway, openai/… and google/… models, while another upstream’s model refuses it). Unset, AskDB assumes nothing: it uses the width the model returns, which it learns when it first builds the index, so the pgvector store doesn’t need it either. |
Changing the ai.embedding provider, model or dimensions changes the index’s embedder id: Studio then reports the RAG index as stale and asks you to reindex before using it.
Reasoning effort
Section titled “Reasoning effort”ai.language.reasoning is an optional, provider-portable knob for how much reasoning/thinking effort AskDB’s model calls use. Leave it unset to keep the provider/model’s own default (AskDB sends no reasoning options at all — this is the default, unchanged behavior).
export default defineConfig({ ai: { provider: "openai", providerConfig: { openai: { apiKey: env("OPENAI_API_KEY") } }, language: { reasoning: { effort: "medium", // global default for every AskDB model call nlToSql: "high", // override: accuracy-sensitive NL→SQL generation enrichment: "low", // override: non-critical enrichment suggestions }, }, }, // ...});| Field | Type | Default | Notes |
|---|---|---|---|
effort | "minimal" | "low" | "medium" | "high" | none | Global default for every AskDB model call. |
nlToSql | Same as effort | effort | Overrides effort for NL→SQL generation calls (ask()). Typically left unset (provider default) or "medium"/"high" — this path is accuracy-sensitive. |
enrichment | Same as effort | effort | Overrides effort for enrichment/suggestion calls (suggestEnrichment()). Safe to bias toward "low"/"minimal" for latency and cost — these are non-critical. |
AskDB maps each value to the provider’s own setting, and sends nothing to a model that doesn’t support reasoning tuning, even when reasoning is set. Bring your own model lists each provider’s setting.
@askdb/client’s createAskDb applies ai.language.reasoning to its ask() calls with no extra code. Bring your own model shows how to set the effort per client or per call, and how to apply it to a model you build yourself.
Azure deployment names
Section titled “Azure deployment names”Azure identifies models by deployment name (e.g. askdb-reporting), which may not match the underlying model id AskDB uses to detect reasoning support. Set ai.language.modelFamily to the real model id — e.g. "gpt-5" or "o3-mini" — when your deployment name doesn’t already look like one.
The introspection block
Section titled “The introspection block”introspection is required. askdb introspect reads it, and its flags override each field for one run (see CLI reference). providerConfig can hold connections for several engines; askdb introspect uses the one provider names.
| Field | Type | Default | Notes |
|---|---|---|---|
provider | "postgres" | "mysql" | "sqlite" | "sqlserver" | "prisma" | Required | The engine to introspect. MariaDB uses mysql. |
providerConfig.postgres.databaseUrl | string | none | Postgres connection URL. Without it, pass askdb introspect --url. |
providerConfig.mysql.databaseUrl | string | none | MySQL or MariaDB connection URL, such as mysql://user:pass@host:3306/database. Without it, pass --url. |
providerConfig.sqlite.file | string | none | Path to an existing .db or .sqlite file, which introspection opens read-only. :memory: doesn’t work: better-sqlite3 can’t open an in-memory database read-only. Without it, pass --url <path>. |
providerConfig.sqlserver.databaseUrl | string | none | SQL Server connection URL: an mssql URI or a Server=…; connection string. Without it, pass --url. |
providerConfig.prisma.schemaPath | string | prisma/schema.prisma, else schema.prisma, in the project root | A schema.prisma file, or a directory of .prisma files. --prisma-schema overrides it. |
outputDir | string | ./askdb/ | Where askdb introspect writes the schema artifact. --out overrides it. askdb ask and Studio read the artifact from here. |
schemas | string[] | Postgres and SQL Server: every non-system schema. MySQL and MariaDB: the URL’s database. | The schemas to introspect, such as ["public", "sales"]. --schemas overrides it. On MySQL and MariaDB these are databases: each becomes its own namespace, and foreign keys between them are kept. |
dialect
Section titled “dialect”| Field | Type | Default | Notes |
|---|---|---|---|
dialect | "postgres" | "cockroachdb" | "mysql" | "mariadb" | "sqlite" | "sqlserver" | The schema artifact’s recorded provider, else postgres | The NL-to-SQL dialect createAskDb uses, and so the CLI, Studio and the HTTP API. When it’s unset and the artifact records a provider with no built-in dialect, they refuse with DialectNotSupportedError rather than guess. askdb-http applies it to its own schema only: a request schemaJson uses the artifact’s recorded provider. @askdb/core’s ask() reads no config: pass dialect to it yourself. |
The dialect normally resolves from the schema artifact (the engine recorded at introspection time). Set dialect only when that inference is wrong — for example, a Prisma schema that declares provider = "postgresql" while your runtime target is a different engine:
export default defineConfig({ // ... dialect: "mysql",});An artifact introspected from MariaDB records mysql, so set dialect: "mariadb" to use the MariaDB dialect.
cockroachdb is a built-in dialect: it reuses the Postgres rules and adds CockroachDB’s reserved words. It sits outside the 1.0 support claim, because AskDB’s end-to-end tests don’t cover it. The 1.0 claim covers PostgreSQL, MySQL, MariaDB, SQLite and SQL Server.
The rag block
Section titled “The rag block”Experimental: rag follows the 0.x @askdb/rag package, so a minor release of @askdb/config may change it (ADR 0030).
The block is optional. Without it, AskDB behaves as if rag: { embedder: "mock", store: "memory", storeConfig: {} } were set: Studio’s RAG page uses the in-memory store and the mock embedder, and getAskDbRuntimeConfig().rag.store is "memory". When the block is present, embedder, store and storeConfig are required. A config that sets ai.embedding but has no rag block fails to load, since nothing would use that model: add rag: { embedder: "ai", … }, or remove ai.embedding.
| Field | Type | Default | Notes |
|---|---|---|---|
embedder | "mock" | "ai" | Required | "mock" is a deterministic lexical embedder that needs no key. Its vectors are 64 wide unless askdb rag --dimensions asks for another width. "ai" is the ai.embedding model. |
store | "file" | "memory" | "pgvector" | Required | The vector store. |
storeConfig | object | Required | The selected store’s options, below. The file and pgvector stores need their branch, even an empty one (storeConfig: { file: {} }). The type requires storeConfig with memory too, but a JavaScript config can leave it out. |
rag.storeConfig
Section titled “rag.storeConfig”| Field | Type | Default | Notes |
|---|---|---|---|
file.basePath | string | <schema dir>/schema: ./askdb/schema with the default outputDir | Path prefix of the file store. It writes <basePath>.embeddings.bin and <basePath>.embeddings.json. A relative path resolves against the working directory. |
memory | {} | none | The in-memory store has no options. |
pgvector.databaseUrl | string | Required with store: "pgvector" | Connection URL of the Postgres database with pgvector. |
pgvector.table | string | askdb_rag_chunks | The table that holds the chunks and their vectors. |
pgvector.indexStrategy | "hnsw" | "ivfflat" | "none" | "hnsw" | The index askdb rag setup-store, askdb rag index and Studio create. "none" means sequential scans. With store: "pgvector", another value fails to load. |
With embedder: "ai", the pgvector table is created at the width the embedding model returns, learned when the index is first built (with ai.embedding.dimensions set, that’s the size requested). An existing table of another width is refused, not overwritten. With embedder: "mock", the table is 64 wide unless askdb rag --dimensions asks for another width. The file store writes its files after every change.
modes and host
Section titled “modes and host”| Field | Type | Default | Notes |
|---|---|---|---|
modes.askdbMode | "schema_only" | "bounded_results" | "schema_only" | The loosest mode a run gets (see below). bounded_results is reserved: today it runs exactly like schema_only. |
modes.omitSensitiveFromPrompt | boolean | false | Leaves sensitive columns, and schema text that names one, out of the prompt. A run can’t turn it off. See Privacy model. |
host.schemaPath | string | none | The schema artifact createAskDb and the HTTP API load when a call names none. askdb ask reads introspection.outputDir instead. |
host.schemaJson | string | none | The schema artifact as inline JSON, for environments without a file system path. When both are set, schemaJson wins. |
export default defineConfig({ // ... modes: { askdbMode: "schema_only", // default omitSensitiveFromPrompt: true, // strict sensitive-column handling }, host: { schemaPath: "./my-app.schema", // default artifact for embedding + HTTP API },});modes.askdbMode is the loosest mode a run gets, on every surface that reads config: the CLI, @askdb/client, and the HTTP API. A run that names no mode uses it. A run can ask for schema_only to tighten it. A run that asks for bounded_results while the config mode is schema_only runs schema_only, with no error; the askdb.pipeline.mode log line records the mode that ran.
modes.omitSensitiveFromPrompt: true works the same way: a run can’t turn it off. @askdb/core’s ask() reads no config, so pass mode to it yourself.
logging and dev
Section titled “logging and dev”logging sets the defaults for the structured JSON logs of the CLI (askdb ask, askdb introspect, askdb rag index and askdb rag query) and the HTTP API server. Studio doesn’t read it. Logs go to stderr, and each CLI flag overrides its field for one run (see Shared logging flags).
| Field | Type | Default | Notes |
|---|---|---|---|
logging.level | "fatal" | "error" | "warn" | "info" | "debug" | "trace" | "silent" | CLI: "silent", or "info" with -v, --log-file or --log-stdout. HTTP server: "info". | Another value fails to load. A logFile or logStdout in config doesn’t raise the CLI’s level: set level too. |
logging.logFile | string | none | Also appends the logs to this file. Parent directories are created. The file stays open for the life of the process: rotate it with copytruncate, or restart the process after a rotate. |
logging.logStdout | boolean | false | Also copies the logs to stdout. |
logging.correlationId | string | A new UUID per run | CLI only: the ID on every log line of a run. --correlation-id overrides it. The HTTP server uses each request’s x-correlation-id header instead, else a new UUID. |
dev.mockSql | string | none | SQL that askdb ask, createAskDb and the HTTP API use in place of the model call, for tests and local development. |
The studio block
Section titled “The studio block”Experimental: studio follows the 0.x @askdb/studio package, so a minor release of @askdb/config may change it (ADR 0030).
| Field | Type | Default | Notes |
|---|---|---|---|
listen.host | string | "127.0.0.1" | Studio’s bind address. askdb studio --host overrides it. |
listen.port | number | 5556 | Studio’s port, an integer from 1 to 65535. --port overrides it. Another value fails when Studio starts. |
execute | object | none | Running SQL from the Playground. See Studio execute configuration. |
Studio execute configuration
Section titled “Studio execute configuration”The studio.execute block configures the Playground’s live execution. It’s off by default: set enabled: true and give Studio its own connection, ideally for a read-only database role. Enable Studio execute shows a config.
| Field | Type | Default | Notes |
|---|---|---|---|
studio.execute.enabled | boolean | false | While off, POST /api/execute returns 403 and the Playground hides Execute. |
studio.execute.provider | "postgres" | "mysql" | "sqlite" | "sqlserver" | The active introspection provider, or "postgres" | See the resolution order below. |
studio.execute.databaseUrl | string | none | Connection URL for Postgres, MySQL and SQL Server. See useIntrospectionConnection. |
studio.execute.file | string | none | SQLite file path. See useIntrospectionConnection. |
studio.execute.useIntrospectionConnection | boolean | false | When true, reuse the introspection connection if databaseUrl / file is unset. |
studio.execute.timeoutMs | number | 30000 | Per-query timeout in milliseconds, a positive integer. Not enforced for SQLite. |
studio.execute.maxRows | number | 500 | Row cap, a positive integer. Results with more rows are truncated. |
Provider resolution order:
studio.execute.provider. Any other value fails to load, so a typo can’t point Execute at another engine.- The active
introspection.providerwhen it is a live engine (postgres,mysql,sqlite,sqlserver). "postgres"for backward compatibility.
Connection resolution (per provider):
- Postgres, MySQL, SQL Server:
studio.execute.databaseUrl→ the introspection URL for the same engine, only whenuseIntrospectionConnection: true. - SQLite:
studio.execute.file→ the introspection SQLite file, only whenuseIntrospectionConnection: true.
Studio doesn’t fall back to your introspection credentials on its own: give execute the connection of a role that only reads. Studio reference — Execute guards describes the read-only transaction, timeout, and row cap applied to every query.
Each execute provider requires its optional peer driver package (pg, mysql2, better-sqlite3, or mssql). See Enable Studio execute — Install the driver for install instructions.
The httpApi block
Section titled “The httpApi block”httpApi configures the askdb-http server and createAskDbHttpServer(). An askdb-http flag or a createAskDbHttpServer() option overrides listen (see HTTP API → Server config).
| Field | Type | Default | Notes |
|---|---|---|---|
listen.port | number | 3000 | The server’s port: an integer from 0 to 65535. NaN counts as unset. Another value fails to load. |
listen.host | string | "127.0.0.1" | The bind address. Bind to 0.0.0.0 only behind a gateway. |
allowSchemaOverride | boolean | false | Accept a per-request schemaJson on POST /ask. An override is a schema artifact the server parses and puts into the prompt through its model key, so enable it only for tests or trusted multi-schema deployments, on @askdb/http-api 1.0.0-beta.48 or later (GHSA-qqx9-qpw2-wcqg). |
requestTimeoutMs | number | 60000 | Aborts the model call of a POST /ask request after this many milliseconds: a positive integer, at most 2147483647. Another value fails to load. |
A platform that sets the port in a PORT variable needs it converted to a number: see Deploy as an HTTP service.
Removed keys
Section titled “Removed keys”A config that sets a key AskDB removed before 1.0 fails to load. The askdb.config: error names each such key and its replacement, and never repeats a value. A key counts as set whatever its value, so a key that reads an unset variable with env("…") fails too. Upgrade AskDB shows each removed key before and after.
Environment variables
Section titled “Environment variables”AskDB loads .env first, then your askdb.config.*. You choose the variable names: they’re whatever you pass to env("…") in your config. This table lists the names askdb init writes by default, and Studio’s setup wizard uses the same ones. Rename any of them in your config and .env together.
| Variable | Config field | Written for |
|---|---|---|
DATABASE_URL | introspection.providerConfig.<engine>.databaseUrl; with --studio-execute, studio.execute.databaseUrl too | --database postgres, mysql or sqlserver. --connection-env gives another name. |
SQLITE_FILE | introspection.providerConfig.sqlite.file | --database sqlite, unless --sqlite-file gives a path or another name. Studio’s setup wizard asks for the file’s path instead. |
PGVECTOR_URL | rag.storeConfig.pgvector.databaseUrl | --rag-store pgvector. --pgvector-env gives another name. |
OPENAI_API_KEY, OPENAI_MODEL | ai.providerConfig.openai.apiKey, ai.language.model | --ai-provider openai, the default. |
ANTHROPIC_API_KEY, ANTHROPIC_MODEL | ai.providerConfig.anthropic.apiKey, ai.language.model | --ai-provider anthropic. |
GOOGLE_GENERATIVE_AI_API_KEY, GOOGLE_AI_MODEL | ai.providerConfig.google.apiKey, ai.language.model | --ai-provider google. |
AZURE_OPENAI_API_KEY, AZURE_RESOURCE_NAME, AZURE_OPENAI_DEPLOYMENT | ai.providerConfig.azure.apiKey and .resourceName (foundry in place of azure for Foundry), and ai.language.model, your deployment name | --ai-provider azure or foundry. |
AI_GATEWAY_API_KEY, ASKDB_AI_MODEL | ai.providerConfig.gateway.apiKey, ai.language.model | --ai-provider gateway. |
--ai-key-env and --ai-model-env give the AI variables other names. A model variable that’s unset leaves ai.language.model to the provider’s default (see ai.language).
Every other setting, such as the output directory, a mode or the log level, is a field in askdb.config.ts, which you can bind to a variable with env("…") too. AskDB reads one variable of its own from the environment, ASKDB_DEBUG, which prints stack traces (see Fix common errors). An ASKDB_* variable you set in the shell does nothing unless your config reads it with env("…").
Custom providers
Section titled “Custom providers”ai.provider, and a section’s provider, take any id, not only the built-in ones. Give a custom provider’s connection its id as the key in ai.providerConfig (apiKey and baseUrl) and its model in ai.language.model. It works only where an adapter is registered under that id, which takes your own code: Bring your own model shows how, and when the openai provider with a baseUrl is enough.
Loading the config
Section titled “Loading the config”The CLI, Studio and the HTTP API load askdb.config.* from the directory they start in, and look nowhere else. bootstrapAskDbEnv() loads it in your own code, and the @askdb/config API lists the file names it tries, in order.
Config precedence
Section titled “Config precedence”For any given setting, the precedence (highest wins) is:
- Per-call arguments — CLI flags (
--schema,--log-level, …) andask()options. - The
askdb.config.*file — the single source of truth for the runtime snapshot. - Built-in defaults applied for optional fields (e.g.
outputDir→./askdb/).
The two modes settings are the exception. They are floors, not defaults: a per-call --mode, mode or omit setting can tighten the config value, never loosen it. See modes and host.
Environment variables don’t override the config file from the outside — they flow through it: every env("VAR") call in the config reads the environment when the file loads. .env is loaded first (without overwriting variables already set in the real environment), so the per-environment override story is: system env beats .env, and whatever env() reads lands in the snapshot. This still lets you ship one config file and vary it per environment — just route each tunable through env().
Read next
Section titled “Read next”© 2026 Yahya Gilany

