Need help with your JSON?

Try our JSON Formatter tool to automatically identify and fix syntax errors in your JSON. JSON Formatter tool

Automated JSON Formatting in Git Hooks

If JSON files keep showing up in pull requests with mixed indentation, inconsistent spacing, or accidental reordering, a Git pre-commit hook is the right place to fix it. The hook can format staged JSON files before the commit is created, which keeps diffs smaller and avoids style debates in code review.

For most JavaScript and TypeScript repositories today, the best default is Prettier + lint-staged + Husky. That setup formats only staged files, works well with git add --patch, and shares the hook configuration with the rest of the team. If you want fewer Node-specific dependencies, a raw Git hook or Python's pre-commit framework can do the same job.

  • Use Husky + lint-staged + Prettier if your repo already has a Node toolchain.
  • Use pre-commit if you want language-agnostic hooks that are easy to pin and update.
  • Use a raw shell hook only if you want the simplest possible setup and understand the staging caveats.

How Git Hooks Fit In

Git runs hook programs from .git/hooks by default, or from another directory if you configure core.hooksPath. The pre-commit hook runs before the commit object is created. If the hook exits with a non-zero status, Git aborts the commit. Developers can still bypass it with git commit --no-verify, so hooks should be treated as fast local guardrails, not your only enforcement layer.

That matters for JSON because formatting is deterministic and cheap. A hook can pretty-print files, reject invalid JSON, and re-stage the corrected version before the commit lands in history.

Recommended Setup: Husky + lint-staged + Prettier

This is the most practical setup for modern web repos. Prettier's own documentation recommends a pre-commit tool, and specifically calls out lint-staged when you need support for partially staged files.

1. Install the formatter and hook tools

pnpm add -D prettier husky lint-staged
pnpm exec husky init

If you use npm, yarn, or bun, use the equivalent install and exec commands. husky init creates a .husky/pre-commit hook and wires Husky into your project setup.

2. Add a lint-staged rule for JSON files

{
  "lint-staged": {
    "*.json": "prettier --write --ignore-unknown"
  }
}

3. Run lint-staged from the pre-commit hook

# .husky/pre-commit
pnpm exec lint-staged

This gives you the behavior most teams want: only staged JSON files are formatted, the updated files are staged again automatically, and partially staged files are handled much more safely than a hand-rolled git add loop.

  • Why Prettier is a good default: it formats JSON consistently without sorting keys.
  • Why lint-staged matters: it targets staged files instead of running on the whole repository.
  • Why Husky is useful: the hook lives in the repository, so the setup is easy to share.

Minimal Shell Hook for Small Repos

If you do not want extra tooling, a plain shell hook still works well for simple repositories. A good pattern is to keep the hook in a committed directory such as .githooks/ and point Git at it with git config core.hooksPath .githooks.

.githooks/pre-commit

#!/bin/sh
files=$(git diff --cached --name-only --diff-filter=ACMR -- '*.json')
[ -z "$files" ] && exit 0

old_ifs=$IFS
IFS='
'
for file in $files; do
  prettier --write --ignore-unknown "$file" || exit 1
  git add "$file" || exit 1
done
IFS=$old_ifs

exit 0

Swap prettier for jq or another formatter if your project is not Node-based. Just be careful with tools that sort keys automatically. For example, jq -S and the default behavior of some hook formatters can reorder object keys, which may create noisy diffs if your team prefers the original logical order.

The tradeoff is staging behavior: a manual hook usually reformats the entire file and re-adds it. That is acceptable for simple workflows, but it is not the safest choice if contributors frequently use git add --patch.

Python pre-commit Alternative

If your team already uses the pre-commit framework, the built-in JSON hooks are a solid option. This keeps formatter versions pinned in one file and works well across polyglot repositories.

.pre-commit-config.yaml

repos:
  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v6.0.0
    hooks:
      - id: check-json
      - id: pretty-format-json
        args: [--autofix, --no-sort-keys]

In this setup, check-json rejects invalid files and pretty-format-json rewrites them in place. The explicit --no-sort-keys flag avoids surprise key reordering. After adding the file, run pre-commit install, and use pre-commit autoupdate occasionally to refresh pinned hook versions.

Common Pitfalls and Current Best Practices

  • Partially staged files: this is the main reason to prefer lint-staged or, in more advanced cases, git-format-staged. Raw hooks that run a formatter and then git add can stage changes the developer did not mean to include.
  • Invalid JSON: the formatter should fail the commit cleanly. That is useful signal, not friction. Fix the syntax, re-stage the file, and commit again.
  • Generated or huge JSON files: skip files that are machine-generated, vendored, or so large that formatting them on every commit becomes slow and noisy.
  • Shared config: keep your formatting rules in one committed place such as .prettierrc, package.json, or .pre-commit-config.yaml.
  • CI still matters: because hooks can be bypassed with --no-verify, add a formatter or validation check in CI if JSON consistency is important for the repository.

Bottom Line

If you want the least surprising setup, use Prettier + lint-staged + Husky. If you want a language-agnostic workflow, use pre-commit with check-json and pretty-format-json. Reserve raw shell hooks for smaller repos where you control the workflow and understand the tradeoffs.

The important part is not the specific tool. It is making JSON formatting automatic, predictable, and fast enough that contributors stop thinking about it.

Need help with your JSON?

Try our JSON Formatter tool to automatically identify and fix syntax errors in your JSON. JSON Formatter tool