Repository navigation
feat(config): read and write config.jsonc and commented JSON configs (CLI-2860, CLI-2861) - #7488
Conversation
…LI-2860) The loader now discovers supabase/config.jsonc and parses both config.json and config.jsonc with jsonc-parser, so comments and trailing commas work and parse errors report a line and column. config.json and config.jsonc together fail with CliConfigFileConflictError. A JSON file next to config.toml still wins, and the CLI now warns that config.toml is ignored. Saves go back to config.jsonc when that is the project's JSON file. The CLI's two hand-rolled comment strippers (VS Code settings in init, deno import maps in functions deploy) use the same parser, as do the experimental feature reader, the upgrade-notice project walk-up and the compute guards.
…-2860) applyConfigEdits now edits config.json and config.jsonc in place with jsonc-parser's modify instead of re-serialising the whole document, so config pull works on JSON configs with comments or trailing commas and leaves untouched text alone. A new key in an existing multi-line object goes after the previous property's line, so a trailing comment stays with its own key and the file's trailing-comma style carries over. The re-parse verification gate is unchanged. ADR 0023 gains an addendum.
saveCliConfig now applies minimal jsonc-parser edits when it saves over an existing config.json or config.jsonc, removing dropped keys by their whole line and keeping strict JSON strict, and falls back to the regenerated text when the edited file does not re-parse to the saved config. A TOML save keeps the file's #:schema directive. init treats an existing config.json or config.jsonc as an existing config and names it when it refuses; init --force and a blank bootstrap remove them when writing the fresh config.toml. compute new records a compute in a JSON config through applyConfigEdits instead of refusing, so the unused ComputeJsonConfigUnsupportedError is removed.
…CLI-2861) On a project whose config is config.json or config.jsonc, `functions new` and the declarative `db pull` path appended TOML to a new config.toml that the JSON file shadows, so the setting never took effect. Both now span-edit the JSON file through applyConfigEdits, keeping its comments, and write it atomically. TOML projects are unchanged.
…2859) Messages, hints and help text that named supabase/config.toml or gave TOML syntax now name the file the project uses and write the key in that file's syntax: `[db] major_version = 17` for config.toml, `db.major_version` to `17` for config.json/config.jsonc. A TOML project sees the same text as before. Where no config is in reach, the text says "your config file" or lists all three file names. - config-advice.ts renders a setting or key for either format, and config-file-ref.ts finds the project's file on paths that have not loaded the config - db-config.toml-read.ts is now db-config.read.ts, since it reads every format - Command help says "the project config file" and uses dotted keys - The stack's version-pin advice now names `local.services.<service>.version` in "your config file" for every project - The published config schema is regenerated for the reworded migration-checks description
…discover-configjsonc-and-parse-json-configs-as-jsonc # Conflicts: # apps/cli/src/command-internal/config-validate.parity.unit.test.ts # packages/config/AGENTS.md
CLI benchmark (Lightweight Commands): no changes foundCommit
API calls: unchanged for all 7 commands. Binary size: 134.7 MB, up 96.0 KB from 134.6 MB. Details: timing ranges, API calls per command, slowest phasesTiming ranges
API calls per command
Slowest phasesNo command moved beyond noise, so there are no phase deltas. Comment |
|
/ai-review |
There was a problem hiding this comment.
🤖 AI Review
Verified all three findings from both available reviews. Confirmed the breaking behavior changes and Windows display-path inconsistency. Refuted the config-write fallback finding because both command paths validate configuration before reaching their writers.
Findings
| Severity | Location | Category | Sources | Claim |
|---|---|---|---|---|
| 🟠 MAJOR | packages/config/src/io.ts:655 |
breaking-change |
claude | Existing projects change behavior: config.json alongside config.jsonc now causes a conflict error; config.jsonc alongside config.toml now takes precedence; init without --force now refuses projects containing only JSON config; and init --force or blank bootstrap now deletes JSON config files. Please change the title to feat(config)!:, add a BREAKING CHANGE: line to the PR description, and retarget the PR to next, since it is currently on develop. |
| ⚪ NIT | apps/cli/src/config/cli-config-values.layer.ts:261 |
cross-platform |
claude | The new config-precedence warning and functions new JSON messages display native backslashes on Windows, unlike the normalized forward-slash paths used by the config advice helper. |
Refuted findings (kept for transparency, not posted as review comments)
apps/cli/src/commands/functions/new/new.handler.ts:64(error-handling): JSON config load failures are treated as absence, so functions new can silently write its configuration to an ignored config.toml.
Refuted: Malformed, conflicting, or unreadable JSON configuration fails the mandatory earlier load. CliConfigValues.load parses through cli-config-values.layer.ts:242–256 without suppressing those errors. functions new reaches that load before creating files or calling appendFunctionConfig. The database path also loads configuration before invoking updateDeclarativeSchemaPathsConfig at db-pull-run.ts:297–302. Thus the reported existing-invalid-config scenario does not reach either TOML fallback.
Stats
Claude findings: 2 · Codex findings: 1 · Confirmed: 2 · Refuted: 1 · Uncertain: 0
Models: claude-opus-5-5 + gpt-6.1-sol · Trigger: manual · Workflow run
This review runs once per PR. A maintainer can request another with a /ai-review comment.
jgoux
left a comment
There was a problem hiding this comment.
Looks good. The JSONC editing holds up across the edge cases I tried (last-key removal, trailing comments, CRLF, comment lines before }), and precedence and conflict handling match the description. Two small P3 notes inline.
…oml (CLI-2861) The functions deploy import_map hint also names a JSON config with forward slashes on Windows.
…discover-configjsonc-and-parse-json-configs-as-jsonc # Conflicts: # apps/cli/src/commands/functions/serve/serve.stack.handler.ts
Summary
The CLI now reads and writes
supabase/config.jsonc, and treatsconfig.jsonthe same way, so comments and trailing commas work and survive every write the CLI makes to the config.Reading:
config.json,config.jsoncandconfig.tomlinsupabase/.config.jsoncreportsformat: "json", so everything that already handles a JSON config treats it the same wayjsonc-parser. A syntax error now names its position, e.g.Comma expected (line 4, column 3), instead of the runtime'sJSON.parsemessageconfig.toml:Ignoring supabase/config.toml because supabase/config.json takes precedence. Delete the file you don't use.init, Deno import maps infunctions deploy) use the same parser now, and the experimental-feature reader and the upgrade notice's project walk-up know aboutconfig.jsoncWriting:
config pulledits a JSON config in place throughjsonc-parser'smodifyinstead of re-serialising the whole file, so comments, trailing commas and untouched values stay as they are. A new key goes after the previous property's whole line, so a trailing comment stays with its own key. ADR 0023 has an addendum for the new JSON strategysaveCliConfigapplies the same minimal edits when it saves over an existingconfig.json/config.jsonc, and removes a dropped key by its whole line. Removing the last key of an object also drops the comma before it, so aconfig.jsonstays strict JSON for older CLIs. If the edited text doesn't re-parse to exactly the saved config, it falls back to writing the regenerated file. A TOML save keeps the file's#:schemalinesaveCliConfigwrites back toconfig.jsoncwhen that's the project's JSON file, and still removes the other config files after the writecompute new(experimental) records the new compute in a JSON config through the same editor, instead of refusingfunctions newand the declarativedb pullwrite theirfunctions.<slug>anddb.migrations.schema_pathsentries into a JSON config through the same editor. Before, both appended TOML to a newconfig.tomlthat the JSON file shadowed, so the setting never appliedinittreats an existingconfig.json,config.jsoncorconfig.tomlas an existing config and names that file when it refuses.init --forceand a blankbootstrapremoveconfig.json/config.jsoncwhen they write the freshconfig.toml, so the new template is the file that gets readMessages:
supabase/config.tomlor gave TOML syntax now name the project's own config file and write the key in its syntax. A TOML project still sees[db] major_version = 17, and a JSON project sees`db.major_version` to `17` in supabase/config.jsonc. Where the command has no config loaded, the text says "your config file" or lists all three file namesdb.seed.sql_pathsdb-config.toml-read.tsis renamed todb-config.read.ts, since it reads every formatjsonc-parseris a new runtime dependency of@supabase/config(MIT, no dependencies of its own). Itsparse()turns a__proto__key into the object's prototype, soparseJsoncbuilds values through itsvisitAPI with own-property assignment instead.Behaviour changes for existing projects
config.jsoncnext toconfig.tomlnow takes over from it. Before,config.jsoncwas never read. The new warning namesconfig.tomlas ignored, so the switch shouldn't go unnoticedconfig.jsonandconfig.jsoncin the samesupabase/directory is now an error:Found both supabase/config.json and supabase/config.jsonc. Keep one and delete the other.Before,config.jsoncwas ignoredconfig.jsonnext toconfig.tomlnow get the warning above.config.jsonalready won there, so which file is read doesn't changeconfig pullandsaveCliConfigon aconfig.jsonnow only change what they write. Before, both rewrote the whole filepin `local.services.<service>.version` to "<version>" in your config filefor every project, including TOML onessupabase/config.toml, config.json or config.jsoncinstead of onlyconfig.tomlinitin a project with only aconfig.json/config.jsoncnow reports the config as already there. Before, it wrote aconfig.tomlthat the JSON file then shadowed.init --forcein such a project now removes the JSON fileLinked issue
Closes CLI-2859
Closes CLI-2860
Closes CLI-2861
🤖 Generated with Claude Code