@@ -217,11 +217,14 @@ SQLSpec CLI supports three ways to specify your database configuration, in order
2172172. **Environment Variable ** (``SQLSPEC_CONFIG ``) - Convenient for development workflows
2182183. **pyproject.toml ** (``[tool.sqlspec] ``) - Project-wide default configuration
219219
220- The ``--config `` option and ``SQLSPEC_CONFIG `` environment variable accept a dotted path to either :
220+ The ``--config `` option and ``SQLSPEC_CONFIG `` environment variable accept:
221221
222222- **A single config object **: ``myapp.config.db_config ``
223223- **A config list **: ``myapp.config.configs ``
224224- **A callable function **: ``myapp.config.get_configs() ``
225+ - **Multiple config paths (comma-separated) **: ``myapp.config.primary_config,myapp.config.analytics_config ``
226+
227+ Each config path is resolved independently, and if a callable returns a list of configs, all configs are collected.
225228
226229Example configuration file (``myapp/config.py ``):
227230
@@ -239,36 +242,36 @@ Config Discovery Methods
239242
240243.. code-block :: bash
241244
242- sqlspec --config myapp.config: get_configs upgrade head
245+ sqlspec --config myapp.config. get_configs upgrade head
243246
244247 Use for one-off commands or to override other config sources.
245248
246249**Method 2: Environment Variable **
247250
248251.. code-block :: bash
249252
250- export SQLSPEC_CONFIG=myapp.config: get_configs
253+ export SQLSPEC_CONFIG=myapp.config. get_configs
251254 sqlspec upgrade head # Uses environment variable
252255
253256 Convenient for development. Add to your shell profile:
254257
255258.. code-block :: bash
256259
257260 # ~/.bashrc or ~/.zshrc
258- export SQLSPEC_CONFIG=myapp.config: get_configs
261+ export SQLSPEC_CONFIG=myapp.config. get_configs
259262
260263 Multiple configs (comma-separated):
261264
262265.. code-block :: bash
263266
264- export SQLSPEC_CONFIG=" app.db: primary_config,app.db: analytics_config"
267+ export SQLSPEC_CONFIG=" app.db. primary_config,app.db. analytics_config"
265268
266269 **Method 3: pyproject.toml (Project Default) **
267270
268271.. code-block :: toml
269272
270273 [tool.sqlspec]
271- config = "myapp.config: get_configs"
274+ config = "myapp.config. get_configs"
272275
273276 Best for team projects - config is version controlled.
274277
@@ -278,22 +281,82 @@ Multiple configs (array):
278281
279282 [tool.sqlspec]
280283 config = [
281- "myapp.config: primary_config",
282- "myapp.config: analytics_config"
284+ "myapp.config. primary_config",
285+ "myapp.config. analytics_config"
283286 ]
284287
285288 **Precedence: ** CLI flag > Environment variable > pyproject.toml
286289
287290If no config is found from any source, SQLSpec will show a helpful error message with examples.
288291
292+ Multi-Config Resolution Details
293+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
294+
295+ When using comma-separated config paths or list format in pyproject.toml, SQLSpec:
296+
297+ 1. **Resolves each path independently **: Each dotted path is imported and resolved
298+ 2. **Flattens callable results **: If a callable returns a list, all configs are collected
299+ 3. **Deduplicates by bind_key **: Later configs override earlier ones with the same ``bind_key ``
300+ 4. **Validates final list **: Empty config lists result in an error
301+
302+ **Deduplication Example: **
303+
304+ .. code-block :: bash
305+
306+ # If primary_config has bind_key="db" and backup_config has bind_key="db"
307+ export SQLSPEC_CONFIG=" app.primary_config,app.backup_config"
308+
309+ # Result: Only backup_config is used (last wins)
310+
311+ **Combined callable and list: **
312+
313+ .. code-block :: python
314+
315+ # myapp/config.py
316+ def get_all_configs ():
317+ """ Returns list of configs."""
318+ return [primary_config, analytics_config]
319+
320+ single_config = AsyncpgConfig(bind_key = " backup" , ... )
321+
322+ .. code-block :: bash
323+
324+ # This resolves to 3 configs: primary, analytics, and backup
325+ export SQLSPEC_CONFIG=" myapp.config.get_all_configs,myapp.config.single_config"
326+
327+ **Deduplication with callables: **
328+
329+ .. code-block :: python
330+
331+ # myapp/config.py
332+ primary = AsyncpgConfig(bind_key = " db" , ... )
333+ updated = AsyncpgConfig(bind_key = " db" , ... ) # Same bind_key
334+
335+ def get_primary ():
336+ return primary
337+
338+ def get_updated ():
339+ return updated
340+
341+ .. code-block :: bash
342+
343+ # Only updated config is used (last wins for bind_key="db")
344+ sqlspec --config " myapp.config.get_primary,myapp.config.get_updated" upgrade
345+
289346 Global Options
290347--------------
291348
292349``--config PATH ``
293- Dotted path to SQLSpec config(s) or callable function. Optional when using
294- environment variable or pyproject.toml config discovery.
350+ Dotted path to SQLSpec config(s) or callable function. Supports comma-separated
351+ multiple paths. Optional when using environment variable or pyproject.toml config discovery.
352+
353+ Examples:
354+
355+ - Single config: ``--config myapp.config.db_config ``
356+ - Callable: ``--config myapp.config.get_configs ``
357+ - Multiple paths: ``--config "myapp.config.primary_config,myapp.config.analytics_config" ``
295358
296- Example: `` --config myapp.config.get_configs ``
359+ Configs with duplicate `` bind_key `` values are deduplicated (last wins).
297360
298361``--validate-config ``
299362 Validate configuration before executing migrations. Shows loaded configs
@@ -808,6 +871,41 @@ Multi-Config Operations
808871When you have multiple database configurations, SQLSpec provides options to manage
809872them collectively or selectively.
810873
874+ Quick Reference: Multi-Config Patterns
875+ ---------------------------------------
876+
877+ .. list-table ::
878+ :header-rows: 1
879+ :widths: 30 35 35
880+
881+ * - Pattern
882+ - Example
883+ - Behavior
884+ * - Single config
885+ - ``--config "app.config.db" ``
886+ - Load one config
887+ * - Config list
888+ - ``--config "app.config.configs" ``
889+ - Load all configs in list
890+ * - Callable returning list
891+ - ``--config "app.config.get_configs" ``
892+ - Call function, load returned configs
893+ * - Comma-separated paths
894+ - ``--config "app.config.db1,app.config.db2" ``
895+ - Load multiple configs, deduplicate by bind_key
896+ * - Env var (comma-separated)
897+ - ``SQLSPEC_CONFIG="app.config.db1,app.config.db2" ``
898+ - Same as comma-separated CLI flag
899+ * - pyproject.toml (list)
900+ - ``config = ["app.config.db1", "app.config.db2"] ``
901+ - Load all paths in array
902+ * - Mixed callables and configs
903+ - ``--config "app.config.get_configs,app.config.backup" ``
904+ - Flatten callable results + direct configs
905+ * - Duplicate bind_key
906+ - ``--config "app.config.old,app.config.new" ``
907+ - Later config overrides (new wins)
908+
811909Scenario: Multiple Databases
812910-----------------------------
813911
@@ -954,6 +1052,38 @@ Best Practices
9541052
9551053 sqlspec --config myapp.config upgrade --dry-run
9561054
1055+ 7. **Use Unique bind_key for Multi-Config **
1056+
1057+ When managing multiple databases, always specify unique ``bind_key `` values:
1058+
1059+ .. code-block :: python
1060+
1061+ # Good - unique bind_keys
1062+ configs = [
1063+ AsyncpgConfig(bind_key = " primary" , ... ),
1064+ AsyncpgConfig(bind_key = " analytics" , ... ),
1065+ ]
1066+
1067+ # Problematic - configs will overwrite each other
1068+ configs = [
1069+ AsyncpgConfig(bind_key = " db" , ... ), # Same key
1070+ AsyncmyConfig(bind_key = " db" , ... ), # Will override above
1071+ ]
1072+
1073+ 8. **Prefer pyproject.toml for Team Projects **
1074+
1075+ Store config paths in version control for consistency:
1076+
1077+ .. code-block :: toml
1078+
1079+ [tool.sqlspec]
1080+ config = [
1081+ "myapp.config.primary_db",
1082+ "myapp.config.analytics_db"
1083+ ]
1084+
1085+ Team members automatically use the same config without manual setup.
1086+
9571087Framework Integration
9581088=====================
9591089
0 commit comments