Skip to content

Configuration reference

Reference · Configuration

AskDB resolves config from two sources: an askdb.config.* file (TypeScript or JavaScript) and environment variables. Both are loaded by @askdb/config at startup into an in-memory runtime snapshot.

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"),
model: env("OPENAI_MODEL"),
},
},
},
introspection: {
provider: "postgres",
providerConfig: {
postgres: { databaseUrl: env("DATABASE_URL") },
},
outputDir: "./my-app.schema",
},
rag: {
embedder: "openai",
store: "pgvector",
storeConfig: {
pgvector: { databaseUrl: env("PGVECTOR_URL") },
},
},
logging: {
level: "info",
},
});

Use the env() helper (rather than process.env) so AskDB can capture which environment variables your config depends on and apply its defaults pass.

defineConfig returns the object unchanged at runtime — it exists only for type inference. The full type is AskDbConfig.

FieldRequiredWhat it configures
aiyesModel provider (provider + providerConfig branch). See Bring your own model.
introspectionyesIntrospection engine (provider: postgres, mysql, sqlite, sqlserver, prisma), its connection (providerConfig), and outputDir (default ./askdb/).
ragyesEmbedder (mock, openai) and vector store (file, memory, pgvector) plus their config branches.
dialectnoOverride the NL-to-SQL dialect (postgres, mysql, sqlite, sqlserver). When unset, it’s inferred from the schema artifact’s recorded provider.
modesnoaskdbMode (schema_only default, bounded_results) and omitSensitiveFromPrompt (default false).
hostnoschemaPath — the default schema artifact for embedding hosts and the HTTP API. schemaJson — inline artifact JSON, for environments without a file system path.
loggingnolevel, plus logFile, logStdout, and correlationId defaults for the CLI’s structured logs.
studionolisten.{host,port} (defaults 127.0.0.1:5556) and the execute block below.
httpApinolisten.{host,port} for the HTTP API server (defaults 127.0.0.1:3000). Use env("PORT") on platforms that inject a port.
devnomockSql — deterministic NL-to-SQL output for tests; bypasses the model call.

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",
});
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
},
});

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") } },
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
},
},
// ...
});
  • effort — global default. One of "minimal" | "low" | "medium" | "high".
  • nlToSql — overrides effort for NL→SQL generation calls (ask()). Typically left unset (provider default) or "medium"/"high" — this path is accuracy-sensitive.
  • enrichment — overrides effort for enrichment/suggestion calls (suggestEnrichment()). Safe to bias toward "low"/"minimal" for latency and cost — these are non-critical.

AskDB maps the portable value to each provider’s native knob via @askdb/ai’s resolveProviderOptions — OpenAI/Azure providerOptions.openai.reasoningEffort, Google Gemini 3.x providerOptions.google.thinkingConfig.thinkingLevel, Gemini 2.5 thinkingConfig.thinkingBudget, Anthropic extended thinking. Models that don’t support reasoning tuning (e.g. gpt-4o-mini, gemini-2.0-flash) never receive these options, even when reasoning is set.

@askdb/client’s createAskDb resolves ai.reasoning automatically for ask() calls — no extra wiring needed. See Bring your own model for the client and programmatic APIs.

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 providerConfig.azure.modelFamily (or ASKDB_AI_AZURE_MODEL_FAMILY) to the real model id — e.g. "gpt-5" or "o3-mini" — when your deployment name doesn’t already look like one.

bootstrapAskDbEnv() looks for config in the current working directory only (no upward walk), trying two locations in order:

  1. askdb.config.<ext> — extension precedence ts → mts → cts → js → mjs → cjs
  2. .config/askdb.<ext> — same extension precedence

The first match wins. JSON config files are not supported. If nothing is found, bootstrapAskDbEnv() throws — run your process from the directory that holds the config (or pass cwd in its options).

AskDB reads .env next to your process via dotenv, then evaluates your askdb.config.*. You choose the variable names — they’re whatever you pass to env("…") in your config. The scaffolded config uses these common names; rename any of them in your config and .env together:

VariableReads into (config field)Notes
OPENAI_API_KEYai.providerConfig.openai.apiKeyStandard OpenAI key.
OPENAI_MODELai.providerConfig.openai.modelOptional model override. Default: gpt-4o-mini.
ANTHROPIC_API_KEYai.providerConfig.anthropic.apiKeyWhen ai.provider = "anthropic". Default model: claude-sonnet-4-6.
AZURE_API_KEY, AZURE_RESOURCE_NAMEai.providerConfig.azure.*Azure OpenAI.
DATABASE_URLintrospection.providerConfig.postgres.databaseUrlPostgres introspection connection.

Everything else AskDB needs — output directory, mode, log level, Studio query connection, the vector-store URL — is set the same way: a field in askdb.config.ts, bound to a name you choose with env("…"). You don’t set any AskDB-prefixed variables yourself; AskDB derives its internal runtime values from your config.

The studio.execute block configures the Query Playground’s live execution feature.

export default defineConfig({
studio: {
execute: {
provider: "mysql", // "postgres" | "mysql" | "sqlite" | "sqlserver"
databaseUrl: env("DATABASE_URL"), // network databases (Postgres, MySQL, SQL Server)
// file: env("SQLITE_FILE"), // SQLite only
},
},
});
FieldEnv keyDefault
studio.execute.providerASKDB_STUDIO_EXECUTE_PROVIDERActive introspection provider, or "postgres"
studio.execute.databaseUrlASKDB_STUDIO_DATABASE_URLIntrospection URL for the active provider
studio.execute.fileASKDB_STUDIO_SQLITE_FILEIntrospection file for SQLite

Provider resolution order:

  1. studio.execute.provider (structured config or ASKDB_STUDIO_EXECUTE_PROVIDER env).
  2. The active introspection.provider when it is a live engine (postgres, mysql, sqlite, sqlserver).
  3. "postgres" for backward compatibility.

Connection resolution (per provider):

  • Postgres: studio.execute.databaseUrlASKDB_STUDIO_DATABASE_URL → introspection Postgres URL.
  • MySQL: studio.execute.databaseUrlASKDB_STUDIO_DATABASE_URL → introspection MySQL URL.
  • SQL Server: studio.execute.databaseUrlASKDB_STUDIO_DATABASE_URL → introspection SQL Server URL.
  • SQLite: studio.execute.fileASKDB_STUDIO_SQLITE_FILE → introspection SQLite file.

Each execute provider requires its optional peer driver package (pg, mysql2, better-sqlite3, or mssql). See Studio — driver packages for install instructions.

ai.provider accepts any string — not just the first-party literals. When an unknown provider string is used, AskDB applies a generic branch: you supply ai.providerConfig.custom.{apiKey, baseUrl, model} (each bound to a name you choose with env("…")), and AskDB hands them to whatever adapter is registered under that provider name.

import { defineConfig, env } from "@askdb/config";
export default defineConfig({
ai: {
provider: "mistral", // any string
providerConfig: {
custom: {
apiKey: env("MISTRAL_API_KEY"),
model: "mistral-large-latest",
},
},
},
// ...
});

This works end to end only when the consuming registry has an adapter registered under that provider name. First-party apps (@askdb/http-api, the CLI) register openai, azure, foundry, google, and anthropic. For any other provider you have two options:

  1. Embed AskDB and pass your own adapter in createAskDb({ providers: [myAdapter] }) — about 40 lines of code.
  2. Use the openai provider with a custom baseUrl for any OpenAI-compatible endpoint (vLLM, OpenRouter, Together, Ollama, …).

See Bring your own model for the embedding walkthrough.

In code that uses the AskDB libraries directly, call bootstrapAskDbEnv() at startup and then read settings via getAskDbRuntimeConfig():

import { bootstrapAskDbEnv, getAskDbRuntimeConfig } from "@askdb/config";
bootstrapAskDbEnv({ cwd: process.cwd() });
const rt = getAskDbRuntimeConfig();
const aiEnv = rt.ai.aiEnv; // provider + key/model env map
const outputDir = rt.introspection.outputDir; // resolved artifact directory

AskDB does not copy the full config into process.env. The runtime snapshot is the source of truth — use getAskDbRuntimeConfig rather than process.env for anything AskDB-specific.

For any given setting, the precedence (highest wins) is:

  1. Per-call arguments — CLI flags (--mode, --schema, …) and ask() options.
  2. The askdb.config.* file — the single source of truth for the runtime snapshot.
  3. Built-in defaults applied for optional fields (e.g. outputDir./askdb/).

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().