Migrating from Other Hook Tools¶
Move one hook at a time when replacing an existing setup. Keep the old hook
available until the equivalent prek hook has run successfully on the whole
repository and in CI.
From pre-commit¶
Start with the two-step path in the Quickstart. The Compatibility and Differences pages cover the cases worth checking when a repository depends on less common behavior.
From lint-staged or Husky¶
A lint-staged command usually becomes a repo = "local" hook.
For example, this hook runs the project's ESLint installation and lets prek
append matching filenames:
The project must install its Node dependencies before this hook runs. Map the rest of the setup as follows:
| Existing concept | prek equivalent |
|---|---|
| lint-staged file glob | files, types, types_or, and exclude |
| Filenames appended to a command | pass_filenames = true, which is the default |
| Command discovers its own files | pass_filenames = false |
| Shell pipeline or expansion | Prefer a direct command; otherwise set shell explicitly |
| Husky hook script | A Git stage plus prek install |
If a Husky script also performs unrelated work, keep that work in a project script and call the script from a local hook. This keeps the Git shim small and makes the command easy to run outside Git.
From Lefthook¶
Translate each Lefthook command into a local hook:
| Lefthook concept | prek equivalent |
|---|---|
Hook name such as pre-commit or pre-push |
Hook stages and an installed Git shim |
commands.<name>.run |
Local hook entry and args |
{staged_files} |
The default pass_filenames = true behavior |
glob and exclude |
files, types, and exclude |
| Parallel command groups | Hooks with the same priority |
Installing a shim and making a hook eligible for that stage are separate choices. For example:
default_install_hook_types = ["pre-commit", "pre-push"]
[[repos]]
repo = "local"
[[repos.hooks]]
id = "tests"
name = "tests"
language = "system"
entry = "cargo test"
pass_filenames = false
stages = ["pre-push"]
Hooks remain sequential when priority is omitted. Give independent hooks the
same explicit priority only after
checking that they do not modify the same files or contend for shared state.
Keep the existing hook during rollout¶
If .git/hooks/<hook-name> already belongs to another tool, a normal
prek install moves it to <hook-name>.legacy and installs prek in migration
mode. The prek shim runs both hook implementations.
When the migration is complete, replace the legacy hook:
Before using --force, make sure the old hook contains no checks that are still
needed. If you uninstall while migration mode is active, prek uninstall
restores the legacy hook to its original path.
Migration checklist¶
- Put each existing check in a local or remote hook.
- Confirm file filtering and whether the command accepts filenames.
- Configure every Git stage that the old tool handled.
- Stage the config and run
prek run --all-files. - Add the same command to CI.
- Install the Git shims, initially preserving the old hook if useful.
- Remove the old tool and dependencies only after local and CI runs agree.