Migration Guide
Use this guide to roll out sqlriver across an existing codebase with minimal churn.
Migrating from holywell 1.x
holywell was renamed to sqlriver in 2.0.0 at the SQL Style Guide author's request. Formatting behavior is unchanged; only the name is.
Swap the package:
npm uninstall holywell
npm install sqlriver
Rename your config and ignore files:
git mv .holywellrc.json .sqlriverrc.json
git mv .holywellignore .sqlriverignore
The old names still work: when the new file is absent and the old one is present, sqlriver reads it and prints a one-line deprecation notice to stderr.
Update the pre-commit hook repo and ids:
repos:
- repo: https://github.com/vinsidious/sqlriver
rev: v2.0.0
hooks:
- id: sqlriver # was: holywell
- id: sqlriver-check # was: holywell-check
Update anything else that invokes the binary by name -- CI jobs (npm install -g sqlriver, sqlriver --check), npm scripts, editor format-on-save commands, and shell completions (sqlriver --completion bash). If you set HOLYWELL_FORCE_FALLBACK_GLOB, rename it to SQLRIVER_FORCE_FALLBACK_GLOB; the old name is still honored.
1) Understand the style model
sqlriver is intentionally opinionated:
- Optional
.sqlriverrc.jsonfor operational settings (maxLineLength,maxDepth,maxInputSize,maxTokenCount,dialect,strict,recover) - No style toggles (indent/casing/alignment modes)
- Deterministic output
Plan for one-time diffs when first applying formatting.
2) Known behavior changes
Before you run sqlriver on existing SQL, understand what will change:
Keywords become uppercase
All SQL keywords are uppercased. select becomes SELECT, inner join becomes INNER JOIN, etc.
ALL-CAPS identifiers become lowercase
ALL-CAPS unquoted identifiers are lowercased to avoid shouting: MYTABLE becomes mytable, USERID becomes userid. Mixed-case identifiers are preserved as-is: MyTable stays MyTable, userId stays userId.
Exception: projection aliases (column aliases in SELECT) are not lowercased, even when ALL-CAPS. SELECT col AS TOTAL keeps TOTAL unchanged.
Quoted identifiers are preserved exactly. "MyTable" stays "MyTable".
Whitespace is normalized
- Trailing whitespace is stripped from every line
- Original indentation is replaced with river-aligned formatting
- Blank lines inside statements are removed
- A trailing newline is added at the end of each statement
Warning: case-sensitive databases
Most databases (PostgreSQL, MySQL, SQL Server) treat unquoted identifiers as case-insensitive, so lowercasing ALL-CAPS identifiers has no effect on query behavior. Mixed-case identifiers are preserved, so this is rarely an issue.
However, if your database or collation is configured to treat unquoted identifiers as case-sensitive (uncommon, but possible in some configurations), the ALL-CAPS lowercasing could change which table or column is referenced. In this case:
- Use quoted identifiers (
"MyTable") for any names that depend on specific casing - Or run
sqlriver --checkfirst to preview changes before applying--write
What does NOT change
- String literals are preserved exactly (
'Hello World'stays'Hello World') - Numeric literals are preserved
- Quoted identifiers are preserved
- Comments are preserved (though their position may shift with reformatting)
- SQL semantics are not altered -- only whitespace and casing change
3) Start in check-only mode
Run in CI without writing changes:
npx sqlriver --check "**/*.sql"
If your repo has generated/vendor SQL, exclude it first:
npx sqlriver --check --ignore "vendor/**" --ignore "generated/**" "**/*.sql"
Or define ignores once in .sqlriverignore:
vendor/**
generated/**
4) Preview changes before writing
Use --dry-run to see what would change without modifying any files:
npx sqlriver --dry-run "**/*.sql"
This implies --check --diff, showing a unified diff for each file that would be reformatted.
5) Batch-format in one commit
Create a dedicated formatting commit:
npx sqlriver --write "**/*.sql"
git add -A
git commit -m "style: apply sqlriver"
Keeping formatting separate from feature changes makes review and rollback easier.
6) Enforce in CI
After baseline formatting, enforce check mode in CI:
npx sqlriver --check "**/*.sql"
Useful companion flag for PR logs:
npx sqlriver --check --list-different "**/*.sql"
7) Add pre-commit guard
Run only on staged SQL files:
npx sqlriver --check $(git diff --cached --name-only -- '*.sql')
Or auto-fix staged files before commit:
npx sqlriver --write $(git diff --cached --name-only -- '*.sql')
git add $(git diff --cached --name-only -- '*.sql')
8) Monorepo rollout strategy
For large repos, migrate package-by-package:
- Format one domain/folder.
- Merge.
- Enable CI check for that scope.
- Repeat until full coverage.
9) Handling unsupported syntax
Both the CLI and the formatSQL API default to recovery mode (recover: true). Statements that fail structural parsing are preserved as raw SQL where possible.
To make parse failures block CI:
npx sqlriver --strict --check "**/*.sql"
For custom tooling, pass recover: false to opt into strict mode.
For a current dialect-by-dialect coverage snapshot, see SQL Dialect Support.