Native mode (without Docker)
Beta: native mode is in beta. Docker remains the default and the recommended way to run MegaLinter, especially on code you do not fully trust: linters (and the configuration files they load) can execute the code of the analyzed repository, and in Docker this happens inside a container.
MegaLinter can run directly on your machine, without a container engine and without downloading a multi-GB image. Only the linters you list are installed, so a run starts in seconds.
Supported platforms: Linux (x86-64 and ARM64), macOS (Apple Silicon), Windows with Git Bash, and WSL (Linux). Intel Macs are not supported: cryptography, needed to verify the MegaLinter package, no longer publishes builds for them. Use Docker there.
Quick start
Requirements:
- uv (Windows:
winget install --id astral-sh.uv -e, macOS:brew install uv) - Node.js, to run
mega-linter-runner - Windows only: Git for Windows (Git Bash),
winget install --id Git.Git -e
-
List the linters allowed to run natively in your
.mega-linter.yml:NATIVE_LINTERS: - PYTHON_BLACK - JAVASCRIPT_ES - MARKDOWN_MARKDOWNLINT -
Install them, then run:
npx mega-linter-runner@beta --install-linters --release beta npx mega-linter-runner@beta --native --release beta
While native mode is in beta, use the beta of mega-linter-runner (@beta): released versions older than native mode do not know these options.
The linter keys are the ones used everywhere else in MegaLinter (ENABLE_LINTERS, DISABLE_LINTERS...). Each linter page has a "native mode" section with its key and the platforms it supports.
Note:
--install-lintersinstalls linters for native mode. It is not--install, which sets up MegaLinter in your repository (configuration and CI files).
NATIVE_LINTERS: explicit opt-in
Nothing runs natively unless it is listed in NATIVE_LINTERS. A linter that is activated by your configuration but not listed is skipped, so you can keep running a larger set of linters in Docker or in CI.
The special value all means every linter matching your configuration:
NATIVE_LINTERS:
- all
Using all is discouraged. It installs many linters, which is slow, and you must fully trust the security of every one of them. Prefer listing the linters you need.
What is installed, and how
Linters are installed in ~/.megalinter (change it with MEGALINTER_HOME), without administrator rights and without touching your system:
| Kind of linter | Installation |
|---|---|
| Python tools | A virtual environment per linter, from pinned packages with hashes |
| Node.js tools | A folder per linter, from a pinned lock file, without running install scripts |
| Binaries and jars | The official release asset, checked against a pinned sha256 |
| Tools provided by the host | Not downloaded: MegaLinter looks for them on your PATH and shows how to install them |
Every download is verified. Upstream signatures and checksums (GitHub attestations, cosign, GPG, release checksum files) are checked when the pinned versions are generated in CI, and the installer only downloads files whose sha256 is pinned in the lock files shipped with MegaLinter. A file that does not match is refused.
Language runtimes
Some linters need a runtime (Node.js, Java, .NET, Go, PowerShell, Dart, PHP...). MegaLinter uses the one installed on your machine when its version is suitable. Otherwise, NATIVE_INSTALL_RUNTIMES decides:
| Value | Behavior |
|---|---|
ask (default) |
Proposes to install the runtime in ~/.megalinter/runtimes (interactive terminals only) |
auto |
Installs it without asking |
never |
Prints how to install it yourself |
Ruby, R and Rust have no portable, verifiable download: install them with your package manager.
Corporate proxies
Downloads go through HTTP_PROXY / HTTPS_PROXY. When your network or antivirus inspects HTTPS connections (uv fails with invalid peer certificate: UnknownIssuer), tell the installers to trust the certificates of your system:
export UV_NATIVE_TLS=1 # uv (MegaLinter itself and Python linters)
export NODE_USE_SYSTEM_CA=1 # Node.js linters
SSL_CERT_FILE, REQUESTS_CA_BUNDLE, NODE_EXTRA_CA_CERTS, PIP_CERT and NPM_CONFIG_CAFILE are given to the installers too.
Security model
- Commands declared by the analyzed repository (
PRE_COMMANDS,POST_COMMANDS),PLUGINSand remoteEXTENDSare ignored in native mode, because they would run on your machine with your privileges. Use--trust-repo-commands(orNATIVE_TRUST_REPO_COMMANDS=truein the environment, never in.mega-linter.yml) only for a repository you fully trust. - Linters only receive an allowlist of system environment variables, so the secrets of your machine (cloud credentials, tokens...) do not leak to them. Add more with
NATIVE_ENV_ALLOWLIST. - Native mode refuses to run when
MEGALINTER_HOMEbelongs to another user or is writable by others. - The
megalinterPython package is installed bymega-linter-runnerafter checking its PyPI attestation: it must have been published by the release workflow of the MegaLinter repository.
Commands
mega-linter-runner forwards to the megalinter command that you can also use directly (uv tool install megalinter --pre):
| Command | Purpose |
|---|---|
megalinter run |
Lint the current folder with the linters of NATIVE_LINTERS |
megalinter install-linters [KEY...] |
Install the given linters, or the ones of NATIVE_LINTERS |
megalinter uninstall-linters KEY... |
Remove installed linters |
megalinter list-linters |
Show the native status of every linter |
megalinter doctor |
Check Git Bash, uv, runtimes and the install folder |
megalinter cache prune |
Empty the download cache |
Faster commands
npx checks its copy of mega-linter-runner and of its dependencies on each call, which adds several seconds to every run. When you run MegaLinter often, install the runner once:
npm install -g mega-linter-runner@beta
mega-linter-runner --native --release beta
Upgrade it with the same npm install -g command.
On Windows and macOS, each parallel worker process starts by loading MegaLinter (about a second). With a few fast linters, fewer workers are quicker: set PARALLEL_PROCESS_NUMBER (for example 2) in your environment, not in .mega-linter.yml, where it would also apply to CI. Measured on a 4-core Windows laptop with 6 linters: 5.0–5.7 s with 2 workers, 9.2–9.9 s with 6.
Pre-commit hook
Native mode makes MegaLinter fast enough to run on each commit with pre-commit:
repos:
- repo: https://github.com/oxsecurity/megalinter
rev: vX.Y.Z # Git tag of a MegaLinter version that includes native mode
hooks:
- id: megalinter-native-incremental # Changed files only, skips the linters that run in project mode
stages:
- pre-commit
- id: megalinter-native-full # Also runs the linters that run in project mode
stages:
- pre-push
- Only the linters of
NATIVE_LINTERSrun, on the files of the commit, and their fixes are applied - The hooks of
rev: vX.Y.Zrun version X.Y.Z ofmega-linter-runnerand of MegaLinter. pre-commit installs the runner once (Node.js is required), instead of resolving it with npx on each commit - Install the linters once with the same version:
npx mega-linter-runner@X.Y.Z --install-linters --release X.Y.Z, as a hook can not ask whether to install a missing language runtime megalinter-incrementalandmegalinter-fullare the same hooks with Docker
Configuration
| Variable | Default | Description |
|---|---|---|
NATIVE_LINTERS |
empty | Linters allowed to run natively (keys, or all) |
NATIVE_INSTALL_RUNTIMES |
ask |
ask, auto or never |
NATIVE_MISSING_LINTERS |
install |
install, skip or fail for a listed linter that is not installed |
NATIVE_ENV_ALLOWLIST |
empty | Extra environment variables given to the linters |
NATIVE_IGNORE_HOST_RUNTIMES |
false |
Ignore the runtimes installed on the host |
NATIVE_OFFLINE |
false |
Install only from the local download cache |
MEGALINTER_HOME |
~/.megalinter |
Where linters, runtimes and downloads are stored |
When MegaLinter runs in Docker and your .mega-linter.yml has no NATIVE_LINTERS, its reports suggest trying native mode. Define NATIVE_SUGGESTIONS: false to hide this suggestion.
Differences with Docker
- Results can differ from Docker: operating system, tool versions provided by the host, file system case sensitivity and path separators.
- Linters installed by MegaLinter always run the version pinned for your MegaLinter version, as in its Docker image. After a MegaLinter upgrade, they are reinstalled at their new version on the next run.
- Tools provided by the host (SwiftLint, Raku, scalafix, xmllint, cppcheck...) run the version installed on your machine. When MegaLinter's Docker image pins a different version, a warning shows both versions.
megalinter list-lintersshows which linters use the version installed on your machine. - Some linters are not available natively on every platform, with the reason shown in their documentation page and by
megalinter list-linters. Use Docker for those. - Flavors do not apply: you choose the linters one by one.