MegaLinter: All-in-One Linting and Code Quality in CI
MegaLinter is a ready-to-use linting orchestrator that runs 100+ linters across all major languages and file types in a single Docker container. Instead of configuring Flake8, ESLint, hadolint, ShellCheck, markdownlint, yamllint, and a dozen others separately, MegaLinter runs all of them with one GitHub Actions workflow. It produces a unified report and only reports errors — not the "I ran successfully" noise.
Why MegaLinter Instead of Individual Linters
Setting up individual linters for each language in a polyglot repository is painful:
- Each linter has its own config format
- Each needs its own CI step
- Report formats differ — some produce JSON, some text, some SARIF
- Version management for each tool adds maintenance overhead
MegaLinter provides:
- One Docker image with all linters pre-installed
- Unified configuration in one
.mega-linter.ymlfile - Consistent SARIF output for all findings
- GitHub PR comments with a summary table
- Auto-fix mode that commits fixes directly
Quick Start: GitHub Actions
The fastest way to enable MegaLinter:
# .github/workflows/mega-linter.yml
name: MegaLinter
on:
push:
branches: [main, develop]
pull_request:
jobs:
megalinter:
name: MegaLinter
runs-on: ubuntu-latest
permissions:
contents: write
issues: write
pull-requests: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: MegaLinter
uses: oxsecurity/megalinter@v8
env:
VALIDATE_ALL_CODEBASE: false # Only lint changed files on PRs
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}That's it. MegaLinter detects all languages in your repository and runs the appropriate linters.
Configuration File
Create .mega-linter.yml in your repository root to customize behavior:
# .mega-linter.yml
# Linters to enable (empty = all applicable linters)
ENABLE_LINTERS:
- PYTHON_RUFF
- PYTHON_MYPY
- JAVASCRIPT_ES
- TYPESCRIPT_ES
- DOCKERFILE_HADOLINT
- BASH_SHELLCHECK
- YAML_YAMLLINT
- JSON_JSONLINT
- MARKDOWN_MARKDOWNLINT
- TERRAFORM_TFLINT
- GO_GOLANGCI_LINT
- DOCKERFILE_HADOLINT
# Linters to disable selectively
DISABLE_LINTERS:
- SPELL_CSPELL # Spell checking produces too many false positives
# File patterns to exclude
FILTER_REGEX_EXCLUDE: "(vendor/|node_modules/|.terraform/|dist/)"
# Only lint changed files in PRs (faster)
VALIDATE_ALL_CODEBASE: false
# Report format
REPORTERS:
- GitHub
- SARIF
# Apply auto-fixes and commit them
APPLY_FIXES: all
APPLY_FIXES_EVENT: push
APPLY_FIXES_COMMIT_MSG: "style: apply MegaLinter auto-fixes"
# Severity threshold
FAIL_IF_ERRORS: trueLanguage-Specific Configuration
MegaLinter picks up existing linter config files (.eslintrc, pyproject.toml, etc.). Override per-linter settings in .mega-linter.yml:
# Python — pass args to Ruff
PYTHON_RUFF_ARGUMENTS: "--config pyproject.toml"
# JavaScript — use existing eslint config
JAVASCRIPT_ES_CONFIG_FILE: ".eslintrc.json"
# Markdown — allow long lines in code blocks
MARKDOWN_MARKDOWNLINT_RULES_PATH: .markdownlint.json
# Terraform — additional args
TERRAFORM_TFLINT_ARGUMENTS: "--config .tflint.hcl"
# ShellCheck severity
BASH_SHELLCHECK_ARGUMENTS: "--severity warning"Flavor Profiles: Smaller Images
MegaLinter's full image is large. Flavor images include only linters for a specific stack:
| Flavor | Languages |
|---|---|
python |
Python, JSON, YAML, Markdown, Shell |
javascript |
JS, TS, JSON, YAML, Markdown |
go |
Go, JSON, YAML, Shell |
java |
Java, JSON, YAML, XML |
terraform |
Terraform, JSON, YAML, Shell |
dotnet |
C#, JSON, YAML |
Use a flavor for faster CI:
- name: MegaLinter
uses: oxsecurity/megalinter/flavors/python@v8
env:
VALIDATE_ALL_CODEBASE: false
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}Auto-Fix Configuration
MegaLinter can commit auto-fixes directly to the PR branch:
# In .mega-linter.yml
APPLY_FIXES: all # or list specific linters: "PYTHON_RUFF,MARKDOWN_MARKDOWNLINT"
APPLY_FIXES_EVENT: push # commit on push
APPLY_FIXES_COMMIT_MSG: "style: [MegaLinter] apply auto-fixes"
# In .github/workflows/mega-linter.yml
permissions:
contents: write # Required for auto-fix commitsAuto-fixes available in MegaLinter include:
- Ruff (Python formatting and fixable lint errors)
- Black (Python formatting)
- isort (Python import sorting)
- ESLint (JavaScript/TypeScript auto-fixable rules)
- Prettier (JS/TS/JSON/YAML/Markdown formatting)
- gofmt (Go formatting)
- terraform fmt (Terraform formatting)
Understanding the MegaLinter Report
MegaLinter produces a report table in PR comments:
| Linter | Files | Fixed | Errors |
|--------|-------|-------|--------|
| PYTHON_RUFF | 45 | 12 | 0 |
| PYTHON_MYPY | 45 | 0 | 3 |
| DOCKERFILE_HADOLINT | 3 | 0 | 1 |
| BASH_SHELLCHECK | 8 | 0 | 0 |Files with errors block the PR (when FAIL_IF_ERRORS: true). Fixed counts show how many auto-fixes were applied.
Detailed logs are available in the CI artifacts:
megalinter-reports/— per-linter logs and error detailsmegalinter-reports/linters-reports/— individual linter outputmegalinter-reports/megalinter-report.sarif— unified SARIF for security integration
SARIF Integration with GitHub Security
Upload SARIF to GitHub's Security tab:
- name: MegaLinter
id: ml
uses: oxsecurity/megalinter@v8
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Upload SARIF
uses: github/codeql-action/upload-sarif@v3
if: always()
with:
sarif_file: megalinter-reports/megalinter-report.sarifLocal MegaLinter Run
Test MegaLinter locally before pushing:
# Run with Docker
docker run -v <span class="hljs-string">"/path/to/repo:/tmp/lint" \
--<span class="hljs-built_in">env VALIDATE_ALL_CODEBASE=<span class="hljs-literal">true \
oxsecurity/megalinter:v8
<span class="hljs-comment"># Use the megalinter-runner script
npx mega-linter-runner --flavor python --fix
<span class="hljs-comment"># Or via the megalinter CLI
npm install -g mega-linter-runner
mega-linter-runner --fixCustomizing Which Files Are Linted
# .mega-linter.yml
# Exclude entire directories
FILTER_REGEX_EXCLUDE: "(^vendor/|^node_modules/|^dist/|^.terraform/|generated/)"
# Include only specific paths for a linter
PYTHON_RUFF_FILTER_REGEX_INCLUDE: "^src/"
# Override file extensions
YAML_YAMLLINT_FILE_EXTENSIONS: [".yaml", ".yml"]Comparing MegaLinter vs Individual Linter Setup
| Aspect | MegaLinter | Individual Linters |
|---|---|---|
| Setup time | 10 minutes | Hours to days |
| Maintenance | Update one image tag | Update each tool separately |
| Coverage | 100+ languages out of box | Only configured languages |
| CI time | ~3-5 min (flavor) / ~8 min (full) | Similar per linter, accumulated |
| Flexibility | Moderate | Full control |
| Auto-fix | Built-in across all linters | Per-tool setup |
MegaLinter is best for polyglot repos, teams without a dedicated DevEx function, and projects that want immediate broad coverage. Individual linter setup is better when you need precise control over each tool's behavior.
Connecting Linting to Quality Assurance
MegaLinter gates code quality at the static analysis level. It ensures your code is consistently formatted, free from common bugs, and follows language-specific best practices. But it doesn't verify behavior.
HelpMeTest adds the behavioral layer — verifying that your quality-gated code actually works correctly in production. Combine MegaLinter for code quality enforcement with HelpMeTest for behavioral monitoring, and you cover the full quality spectrum from commit to production.
Summary
- MegaLinter runs 100+ linters in one Docker container — no per-tool configuration needed
VALIDATE_ALL_CODEBASE: falselints only changed files in PRs — fast feedback on large repos- Flavor images (python, javascript, go, etc.) are significantly smaller than the full image
APPLY_FIXES: all+ write permissions auto-commits fixes to PR branches- SARIF output integrates all linting findings into GitHub Security tab
- Per-linter config files (
.eslintrc,pyproject.toml) are automatically picked up