1
0
mirror of https://github.com/j178/prek.git synced 2026-04-03 17:34:03 +02:00
Files
prek/docs/languages.md
2026-01-27 15:50:16 +08:00

16 KiB

Language support

What “language” means in prek

Each hook has a language that tells prek how to install and run it. The language determines:

  • Whether prek creates a managed environment for the hook
  • How dependencies are installed (additional_dependencies)
  • How toolchain versions are selected (language_version)
  • How entry is executed

For repo: local hooks, language is required. For remote hooks, it is read from .pre-commit-hooks.yaml, but you can override it in your config.

Toolchain management and language_version

prek resolves toolchains in two steps:

  1. Discover system toolchains (PATH and common version manager locations).
  2. Download a toolchain when the language supports it and the request cannot be satisfied locally.

If language_version is system, prek skips downloads and requires a system-installed toolchain. If language_version is default, prek uses the language’s default resolution logic (often preferring system installs, then downloading if supported).

!!! note "prek-only"

`language_version` is parsed as a version request. For languages that use semver requests, you can specify ranges (for example `^1.2`, `>=1.5, <2.0`). See [Configuration](configuration.md#language_version) for details.

Languages with managed toolchain downloads in prek today:

Other supported languages rely on system installations and will fail if a matching toolchain is not available.

Language details

Below is how prek handles each language (with notes when it differs from pre-commit).

bun

Status in prek: Supported.

prek installs Bun hooks via bun install and runs the configured entry. The repository should contain a package.json. entry should match a provided bin name or be a Bun command. additional_dependencies are supported.

Bun hooks run without needing a pre-installed Bun runtime when toolchain download is available.

language_version

Supported formats:

  • default or system
  • bun, bun@latest
  • bun@1, 1
  • bun@1.1, 1.1
  • bun@1.1.0, 1.1.0
  • Semver ranges like >=1.0, <2.0
  • Absolute path to a Bun executable

!!! note "prek-only"

Bun language support is a prek extension. pre-commit does not have native `bun` support.

conda

Status in prek: Not supported yet.

Tracking: #52

coursier

Status in prek: Not supported yet.

Tracking: #53

dart

Status in prek: Not supported yet.

Tracking: #51

docker

Status in prek: Supported.

prek expects the hook repository to ship a Dockerfile and builds the image from the repo root with docker build .. Hooks run inside the container, and the first token of entry is used as the container entrypoint (arguments are passed after it).

Runtime behavior:

  • Requires a working container engine on the host (Docker, Podman, or Container).
  • The repository is bind-mounted into the container at /src and the working directory is set to /src.
  • The container is run with --entrypoint set to the hook entry, so the image’s default command is not used when filenames are passed.
  • Environment variables configured via env are passed using -e.
  • On Linux, prek tries to run as a non-root user and handles rootless Podman with --userns=keep-id.

Use docker when you need a language runtime that isn’t otherwise supported; the container provides the execution environment.

!!! note "prek-only"

prek auto-detects the container runtime (Docker, Podman, or [Container](https://github.com/apple/container)) and can be overridden with `PREK_CONTAINER_RUNTIME`.
See [Configuration](configuration.md#environment-variables) for details.

docker_image

Status in prek: Supported.

prek runs hooks from an existing image. The entry value is passed to docker run directly, so it should include the image reference and can optionally include --entrypoint overrides.

Runtime behavior:

  • Uses the same bind-mount and /src working directory as docker hooks.
  • Environment variables configured via env are passed using -e.

If the image already defines an ENTRYPOINT, you can omit --entrypoint in entry. Otherwise, specify it explicitly in entry.

!!! note "prek-only"

prek uses the same runtime auto-detection as `docker` hooks.

dotnet

Status in prek: Not supported yet.

Tracking: #48

fail

Status in prek: Supported.

fail is a lightweight “forbid files” hook. The entry text is printed when the hook fails, followed by the list of matching files, and the hook exits non-zero.

golang

Status in prek: Supported.

prek installs with go install ./... in an isolated GOPATH. The repository should build at least one binary whose name matches the hook entry. additional_dependencies can be appended and language_version selects the Go toolchain.

language_version

Supported formats:

  • default or system
  • go1.22, 1.22
  • go1.22.1, 1.22.1
  • Semver ranges like >=1.20, <1.23
  • Absolute path to a go executable

Pre-release strings (for example go1.22rc1) are not supported yet.

haskell

Status in prek: Not supported yet.

Tracking: #1445

julia

Status in prek: Not supported yet.

Tracking: #1446

lua

Status in prek: Supported.

prek installs Lua hooks via LuaRocks and runs the configured entry. If the repository includes a rockspec, it is installed into the hook environment before running.

language_version

Lua does not support language_version today. It uses the system lua / luarocks installation.

The hook entry should point at an executable installed by LuaRocks.

node

Status in prek: Supported.

prek expects a package.json and installs via npm install ., exposing executables from the package bin. entry should match a provided bin name. additional_dependencies are supported.

Node hooks run without needing a pre-installed Node runtime when toolchain download is available.

language_version

Supported formats:

  • default or system
  • node18, 18, 18.19, 18.19.1
  • Semver ranges like ^18.12 or >=18, <20
  • LTS selectors: lts or lts/<codename>
  • Absolute path to a Node executable

perl

Status in prek: Not supported yet.

Tracking: #1447

python

Status in prek: Supported.

prek installs hook repositories with uv pip install and uses the installed console scripts. The repository should be installable via pip (for example via pyproject.toml or setup.py). additional_dependencies are appended to the install step.

Python hooks run without requiring a system Python when toolchain download is available.

language_version

Supported formats:

  • default or system
  • python, python3, python3.12, python3.12.1
  • 3, 3.12, 3.12.1
  • Wheel-style short forms like 312 or python312
  • Semver ranges like >=3.9, <3.13
  • Absolute path to a Python executable

!!! note "prek-only"

prek uses `uv` for virtual environments and dependency installs, and can auto-install Python toolchains based on `language_version`.

Dependency management with uv

prek uses uv for creating virtual environments and installing dependencies:

  • First tries to find uv in the system PATH
  • If not found, automatically installs uv from the best available source (GitHub releases, PyPI, or mirrors)
  • Automatically installs the required Python version if it's not already available

!!! warning "Environment variables"

Since prek calls `uv` under the hood to create Python virtual environments and install dependencies, most `uv` environment variables will affect prek's behavior. For example, setting `UV_RESOLUTION=lowest-direct` in your environment will cause hook dependencies to be resolved to their lowest compatible versions, which may lead to installation failures with old packages on modern Python versions.

If you encounter unexpected behavior when installing Python hooks, check whether you have any `UV_*` environment variables set that might be affecting dependency resolution or installation.

PEP 723 inline script metadata support

For Python hooks without additional_dependencies, prek can read PEP 723 inline metadata from the script specified in the entry field.

Example:

.pre-commit-config.yaml:

repos:
  - repo: local
    hooks:
      - id: echo
        name: echo
        language: python
        entry: ./echo.py

echo.py:

# /// script
# requires-python = ">=3.13"
# dependencies = [
#     "pyecho-cli",
# ]
# ///

from pyecho import main
main()

Important notes:

  • The first part of the entry field must be a path to a local Python script
  • If additional_dependencies is specified in .pre-commit-config.yaml, script metadata will be ignored
  • When both language_version (in config) and requires-python (in script) are set, language_version takes precedence
  • Only dependencies and requires-python fields are supported; other metadata like tool.uv is ignored

r

Status in prek: Not supported yet.

Tracking: #42

ruby

Status in prek: Supported (with limitations).

prek installs gems from a *.gemspec and runs executables declared in the gemspec. additional_dependencies are installed into the same isolated gemset.

language_version

Supported formats:

  • default or system
  • 3, 3.3, 3.3.6
  • ruby-3, ruby-3.3, ruby-3.3.6
  • Semver ranges like >=3.2, <4.0
  • Absolute path to a Ruby executable

!!! note "prek-only"

prek does not automatically download Ruby toolchains. It uses system-installed Rubies, including common version managers, and fails if no suitable version matches `language_version`.

Tracking for Ruby toolchain download support: #43

Gems specified in hook gemspec files and additional_dependencies are installed into an isolated gemset shared across hooks with the same Ruby version and dependencies.

rust

Status in prek: Supported.

prek installs binaries via cargo install --bins and runs the specified executable. The repository should contain a Cargo.toml that produces the binary referenced by entry. additional_dependencies and language_version are supported.

language_version

Supported formats:

  • default or system
  • Channels: stable, beta, nightly
  • 1, 1.70, 1.70.0
  • Semver ranges like >=1.70, <1.72

!!! note "prek-only"

- prek supports installing packages from virtual workspaces. See [#1180](https://github.com/j178/prek/pull/1180).
- `additional_dependencies` supports:
    - Library dependencies using `name` or `name:version` (applied via `cargo add`).
    - CLI dependencies using `cli:`. These can be crates.io packages (`cli:rg:13.0.0`) or git URLs (`cli:https://github.com/BurntSushi/ripgrep:13.0.0`).

swift

Status in prek: Supported.

prek detects the system Swift installation and runs hooks using the configured entry. If the hook repository contains a Package.swift, prek builds it in release mode and adds the resulting binaries to PATH.

Runtime behavior:

  • Uses the system Swift installation (no automatic toolchain management)
  • Builds Swift packages with swift build -c release
  • Build artifacts are stored in the hook environment's .build/release/ directory
  • The entry command runs with built binaries available on PATH

language_version

Swift does not support language_version today. It uses the system swift installation.

pygrep

Status in prek: Supported.

prek provides a Python-based grep implementation for file content matching. The entry is a Python regex. Supported args:

  • -i / --ignore-case
  • --multiline
  • --negate (require all files to match)

Regex matching uses Python’s re semantics for compatibility with pre-commit.

system

Status in prek: Supported.

system runs a system executable without a managed environment. The command is taken from entry, and filenames are appended unless pass_filenames: false is set. Dependencies must be installed by the user.

Use system for tools with special environment requirements that cannot run in isolated environments.

!!! note

`unsupported` is accepted as an alias for `system`.

script

Status in prek: Supported.

script runs repository-local scripts without a managed environment. For remote hooks, entry is resolved relative to the hook repository root; for local hooks, it is resolved relative to the current working directory.

Inline scripts

prek supports inline scripts for language: script, so you can put a small script directly in entry.

How prek decides “inline script” vs “script path”

  • If entry does not contain a newline, it is treated as a normal command/script path.
  • If entry does contain a newline, it is treated as an inline script unless the first token resolves to a real file in the repository (or current working directory for repo: local).

This means YAML block scalars are safe to use for readability even when entry is a script path.

How inline scripts are executed

  • The inline content is written to a temporary file.
  • If the first line has a shebang (#!), prek executes the temp file and lets the OS/shebang decide the interpreter.
  • If there is no shebang, prek chooses a default shell:
    • On Unix: prefers bash -e, falls back to sh -e.
    • On Windows: prefers pwsh, then powershell, then cmd.exe.

Any hook arguments (args) and selected filenames are passed as arguments to the interpreter/script. For POSIX shells, use "$@" to read the filenames; for PowerShell, use $args.

Examples

Inline script without a shebang (uses the default shell):

repos:
    - repo: local
        hooks:
            - id: inline
                name: inline
                language: script
                entry: |
                    echo "hello"
                    printf 'args:'
                    printf ' %s' "$@"
                    printf '\n'
                verbose: true

Inline script with a shebang (interpreter comes from the script content):

repos:
    - repo: local
        hooks:
            - id: inline-bash
                name: inline-bash
                language: script
                entry: |
                    #!/usr/bin/env -S bash -e
                    echo "running under bash"
                    echo "args: $*"
                verbose: true

Multiline entry, but still a script path (first token is an existing file):

repos:
    - repo: local
        hooks:
            - id: script-path
                name: script-path
                language: script
                entry: |
                    ./script.sh --from-entry
                pass_filenames: false

Use script for simple repository scripts that only need file paths and no managed environment.

!!! note

`unsupported_script` is accepted as an alias for `script`.

deno

Status in prek: 🚧 WIP.

prek has experimental support in progress. pre-commit does not have a native deno language.

Tracking: #619

If you want to help add support for the missing languages, check open issues or start a discussion in the repo.