Migration Guide
Use this guide to roll out holywell across an existing codebase with minimal churn.
1) Understand the style model
holywell is intentionally opinionated:
- Optional
.holywellrc.jsonfor operational settings (maxLineLength,maxDepth,maxInputSize,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 holywell on existing SQL, understand what will change:
Keywords become uppercase
All SQL keywords are uppercased. select becomes SELECT, inner join becomes INNER JOIN, etc.
Unquoted identifiers become lowercase
Unquoted table and column names are lowercased. MyTable becomes mytable, UserID becomes userid.
Quoted identifiers are preserved exactly. "MyTable" stays "MyTable".
Whitespace is normalized
- Leading and trailing whitespace is stripped from every line
- 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 them has no effect on query behavior.
However, if your database or collation is configured to treat unquoted identifiers as case-sensitive (uncommon, but possible in some configurations), 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
holywell --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 holywell --check "**/*.sql"
If your repo has generated/vendor SQL, exclude it first:
npx holywell --check --ignore "vendor/**" --ignore "generated/**" "**/*.sql"
Or define ignores once in .holywellignore:
vendor/**
generated/**
4) Batch-format in one commit
Create a dedicated formatting commit:
npx holywell --write "**/*.sql"
git add -A
git commit -m "style: apply holywell"
Keeping formatting separate from feature changes makes review and rollback easier.
5) Enforce in CI
After baseline formatting, enforce check mode in CI:
npx holywell --check "**/*.sql"
Useful companion flag for PR logs:
npx holywell --check --list-different "**/*.sql"
6) Add pre-commit guard
Run only on staged SQL files:
npx holywell --check $(git diff --cached --name-only -- '*.sql')
Or auto-fix staged files before commit:
npx holywell --write $(git diff --cached --name-only -- '*.sql')
git add $(git diff --cached --name-only -- '*.sql')
7) 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.
8) Handling unsupported syntax
In recovery mode (default), unknown constructs are preserved as raw SQL where possible. If you need strict parse failures, use API parse options with recover: false in custom tooling.