NL2SQL 0.5.0
Configuration v2: one nl2sql.yaml configures the engine, the CLI, nl2sql-api and the demo, an extension registry loads adapters, LLM, embeddings and secret providers by name, and every engine owns its config. This is a clean break from 0.4, with no compatibility layer: read Upgrading before you install it.
Released 2026-10-14.
Highlights
- One config file.
nl2sql.yamlreplaces the 0.4 files and about 48 environment variables. It can be one file or split intodatasources/,llm.yaml,embeddings.yaml,policies.yamlandstorage.yaml.nl2sql initwrites that layout for you (--demoadds the demo databases).nl2sql config checkchecks every file, name, driver and secret without starting the engine, and with--connectit also connects to each datasource. It fits a CI job. - An extension registry.
Registry.default()finds adapters, LLM providers, embeddings providers and secret providers through entry points, and imports none of them until the config uses one. Register your own withadd_adapter,add_llm,add_embeddings,add_secretsor a decorator (@registry.adapter("name")). A wrong interface version, a missing driver or a misspelled name is reported when the engine is built, with the fix. The SDK they build against is nownl2sql-sdk(import nl2sql_sdk). - A tidier Python API, with a model switch at runtime.
run_queryandstream_querystay at the top level. Everything else is in namespaces:engine.datasources,index,llm,policies,curated,results,tracesandfeedback, plusabout(),check()andclose()(orwith).engine.llm.replace(...)and the admin-onlyPUT /api/v1/settings/llmswap the model in a running engine. Queries already running finish on the old model, and the change is logged without keys. - Each engine owns its config. There are no process-wide settings and nothing writes
os.environ, so two engines in one process share nothing.import nl2sqltakes about 15 ms instead of about 2.2 s, because it loads no heavy library.
What's included
Features
nl2sql-adapter-sdkis renamednl2sql-sdk, with the import packagenl2sql_sdk(#262).import nl2sqlloads no database driver, vector store or model library, and a test holds it under budget (#263).- The typed config models,
load_config,file:includes,${env:...}references, strict keys with "did you mean", and oneConfigErrorthat lists every problem (#264). - The SDK defines the adapter and secret provider interfaces, with interface versions, driver lists and install hints. Secret provider settings are checked strictly (#265).
- The extension registry:
Registry.default(),add_*, decorators, and the entry point groupsnl2sql.adapters,nl2sql.llms,nl2sql.embeddingsandnl2sql.secrets(#266). nl2sql init [DIR] [--demo] [--provider NAME] [--force]writes the split config layout and checks it (#267).- The engine is built from a
Config:NL2SQL(config),NL2SQL.from_config(path),NL2SQL.demo(),check()andclose(). Building never connects, and all results are written understorage.path(#268). - The pipeline reads its settings from its own engine, so two engines in one process each keep their own row limit, plan cache and model (#269).
engine.llm.replace, with LLM clients cached per engine, and a plan cache key that includes the planner's model (#270).- Indexing, tracing, replay and benchmarks run on run-scoped settings and never change the engine they run on (#271).
- The CLI,
nl2sql-apiand the demo start fromnl2sql.yamlwith a single--configflag.nl2sql setupand every 0.4 config path are removed (#272). nl2sql config check [--connect], which is also callable from Python asnl2sql.config.check.check_config(#273).- The namespaced facade and
PUT /api/v1/settings/llm. The CLI now uses only the public API (#274). engine.feedback,engine.traces.get,engine.about()andengine.llm.providers(). The playground now uses only the public API (#275).- The process-wide settings object is deleted. The library writes no environment variables and reads only an allow-list of them (#276).
Fixes
- Secrets in the config are masked when it is printed,
NL2SQL_LOG_LEVELset in.envtakes effect, and the scripts no longer write the environment (#277).
Docs
- The design for Configuration v2 and the extension registry (#260). The Configuration pages are rewritten for
nl2sql.yamlin the PRs above.
Known limits
- Running several
nl2sql-apireplicas is not supported for a model switch.PUT /api/v1/settings/llmchanges only the process that receives it, and the change is not saved: a restart readsllm.yamlagain. - There is no migration command. You map 0.4 files and variables by hand, using the table.
- Results are stored locally only. The S3 and ADLS backends are gone until the results-store interface in Phase 2.
nl2sql initis not interactive, and its--provideracceptsopenai,anthropicandopenrouteronly (Ollama has no default model). The guided setup flow comes in Phase 4.- A datasource's
connectionblock is checked by the adapter only, not by a typed model, andcheck()gives a generic reason when a connection fails. Typed connection models and connection-test stages come with SDK v2 in Phase 2. - After
engine.datasources.remove(id), the datasource's index entries stay until the next fullindex.buildorindex.clear. - This release is Phase 1 of five. Phase 2 brings SDK v2, storage interfaces and policy globs, Phase 3 the event bus and evals, Phase 4 the guided setup and the web app on
nl2sql-api, and Phase 5 glossaries and knowledge sources.
Upgrading
Adapter and secret provider authors: pip install "nl2sql-sdk==0.5.0" and uninstall nl2sql-adapter-sdk.
Breaking changes: many. 0.5 is a clean break with no compatibility layer, and the engine refuses a 0.4 config. Start with nl2sql init, then move your values across with the 0.4 to 0.5 mapping.
- One config file (#264, #272).
configs/datasources.yaml,llm.yaml,policies.json,secrets.yaml,curated.yaml,sample_questions.yamland about 48 environment variables are no longer read. What to do: runnl2sql init(ornl2sql init --demo) and move each value to its new place using the mapping table. Sample questions now sit on each datasource, policies are YAML, and LLM agents are keyed by node name (ast_planner). - Environment variables (#276). Only
NL2SQL_CONFIG,NL2SQL_LOG_LEVELand the provider keys (OPENAI_API_KEY,ANTHROPIC_API_KEY,OPENROUTER_API_KEY) are read directly. What to do: write any other value in the YAML, as${env:VAR}where it should come from the environment. .envloading (#272). Only the CLI,nl2sql-apiandnl2sql demoload a.env, and only the one next tonl2sql.yaml. They never override a variable that is already set. The library never reads.env.--env,--env-file,ENV,APP_ENVandENV_FILE_PATHare gone. What to do: put.envnext tonl2sql.yaml. From Python, callnl2sql.load_env_file(path)before building the engine.nl2sql setupis removed (#272). What to do: usenl2sql init, ornl2sql init --demoin place ofsetup --demo.- One CLI flag (#272).
nl2sql --config PATH/nl2sql.yaml <command>(orNL2SQL_CONFIG, or./nl2sql.yaml) replaces every per-command path flag (--llm-config,--secrets-config,--policies-config,--vector-store, and thecuratedandpolicypath flags). What to do: pass--configonce, before the command. nl2sql-apisettings (#272). TheNL2SQL_API_*variables are removed. What to do: setapi.role_header,api.role,api.trust_body_roleandapi.cors_origins(a list) in anapi:section, and the admin roles inpolicies.admin_roles. The API image readsNL2SQL_CONFIG=/etc/nl2sql/nl2sql.yaml, so mount your config folder there.- REST LLM route (#274).
POST /api/v1/llmis replaced by the admin-onlyPUT /api/v1/settings/llm, whose body is thellmsection as JSON. A bad body gets a 422 with the config error.POST /api/v1/datasourcetakes the datasource in thenl2sql.yamlshape, and the datasource routes returnDatasourceInfo. What to do: update your clients. - Result storage (#268). The S3 and ADLS backends and the
RESULT_ARTIFACT_*settings are removed. Results are written understorage.path/results/. What to do: setstorage.pathand copy anything you need from a remote store yourself. - Secret providers (#265).
hashiis renamedhashicorp, with no alias. TheVAULT_ADDR,VAULT_TOKENandAZURE_KEYVAULT_URLfallbacks are removed, and an unknown provider setting is an error. What to do: writetype: hashicorpand giveurlandtoken(for exampletoken: "${env:VAULT_TOKEN}"), orvault_urlfor Azure, in the provider's block. - The SDK package (#262).
nl2sql-adapter-sdk/nl2sql_adapter_sdkis nownl2sql-sdk/nl2sql_sdk. Adapters also declareinterface_version,driver_modulesandinstall_hint(#265). What to do: rename the dependency and the imports, add the three class attributes, and register through thenl2sql.adaptersentry point orRegistry.add_adapter. - The Python facade (#274, #275). The flat methods,
engine.context,engine.query,get_adapter,configure_llm,reload_llm_config, theauth,settings,policy,indexinganddatasourcesub-APIs, and theQueryAPI/DatasourceAPI/LLM_API/... exports are removed.NL2SQL()is built from aConfigorNL2SQL.from_config(path). What to do: call the namespaces (engine.datasources.add,engine.index.build,engine.llm.replace,engine.policies.validate, ...). The public facade page lists them. - Hosted demo (#276).
nl2sql demo --hostedrefuses to start ifOPENAI_API_KEY,OPENROUTER_API_KEYorANTHROPIC_API_KEYis set in its environment.NL2SQL_DEMO_HOSTEDandNL2SQL_DEMO_QUESTIONS_*are replaced by--hosted,--questions-per-minuteand--questions-per-session, and the demo's key file is<dir>/.envinstead of.env.demo(#272). What to do: remove provider keys from the hosted server's environment and use the flags. - Startup errors (#268). Anything wrong that can be found without connecting is now a
ConfigErrorwhen the engine is built. This includes an unknown datasource type and a secret that does not resolve, which in 0.4 only marked that datasource unavailable. A datasource that cannot connect still runs degraded unless it isrequired: true. What to do: runnl2sql config checkbefore you deploy.
What's next
Next: 0.6, datasources and adapter SDK v2, then the web app on the API and Docker Compose.
Full changelog: v0.4.1...v0.5.0