Skip to main content
Vale is designed for CI/CD integration, with predictable exit codes, multiple output formats, and support for all major CI platforms.

Exit Codes

Vale uses standard exit codes to indicate success or failure:
  • 0: No errors found (warnings and suggestions may be present)
  • 1: One or more errors found
  • 2: Runtime error (configuration issue, file not found, etc.)
From cmd/vale/main.go:82,129:
func handleError(err error) {
    ShowError(err, Flags.Output, os.Stderr)
    os.Exit(2)
}

if hasErrors && !Flags.NoExit {
    os.Exit(1)
}
Use the --no-exit flag to prevent Vale from exiting with code 1 on errors. This is useful for reporting-only scenarios.

Output Formats

Vale supports multiple output formats optimized for different CI systems.

JSON Output

Perfect for programmatic parsing:
vale --output=JSON *.md
Output structure:
{
  "README.md": [
    {
      "Action": {
        "Name": "replace",
        "Params": ["use"]
      },
      "Check": "MyStyle.Terms",
      "Description": "",
      "Line": 5,
      "Link": "https://example.com/style-guide",
      "Message": "Use 'use' instead of 'utilize'",
      "Severity": "error",
      "Span": [12, 19],
      "Match": "utilize"
    }
  ]
}
From cmd/vale/json.go:10-23, Vale groups alerts by file path.

Line Output

Compatible with most CI parsers:
vale --output=line *.md
Output format:
README.md:5:12:MyStyle.Terms:Use 'use' instead of 'utilize'
README.md:8:1:MyStyle.Headings:'introduction' should be capitalized
Format: <path>:<line>:<col>:<check>:<message> This format is compatible with:
  • GitHub Actions problem matchers
  • GitLab CI error formats
  • Jenkins console parsers
  • VS Code problem matchers

CLI Output

Human-readable output for local development:
vale *.md

GitHub Actions

Integrate Vale using the official action or a custom workflow.

Using the Official Action

1

Create workflow file

Create .github/workflows/vale.yml:
.github/workflows/vale.yml
name: Vale Linting
on: [pull_request]

jobs:
  vale:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: errata-ai/vale-action@reviewdog
        with:
          files: docs
        env:
          GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
2

Configure Vale

Add .vale.ini to your repository:
.vale.ini
StylesPath = .github/styles
MinAlertLevel = suggestion

Packages = Microsoft, write-good

[*.md]
BasedOnStyles = Vale, Microsoft
3

Sync styles on install

The action automatically runs vale sync to download packages.

Custom GitHub Actions Workflow

For more control, create a custom workflow:
.github/workflows/vale.yml
name: Vale

on:
  pull_request:
    paths:
      - '**.md'
      - '**.mdx'
      - '.vale.ini'
      - '.github/workflows/vale.yml'

jobs:
  vale:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v3
      
      - name: Install Vale
        run: |
          wget https://github.com/errata-ai/vale/releases/latest/download/vale_Linux_64-bit.tar.gz
          tar -xvzf vale_Linux_64-bit.tar.gz
          sudo mv vale /usr/local/bin/
      
      - name: Sync styles
        run: vale sync
      
      - name: Run Vale
        run: vale --output=line --minAlertLevel=warning docs/
Pin to a specific Vale version for reproducible builds:
wget https://github.com/errata-ai/vale/releases/download/v3.0.0/vale_Linux_64-bit.tar.gz

GitLab CI

Integrate Vale into GitLab CI/CD pipelines.

Basic Integration

.gitlab-ci.yml
stages:
  - test

vale:
  stage: test
  image: golang:1.25
  script:
    - wget https://github.com/errata-ai/vale/releases/latest/download/vale_Linux_64-bit.tar.gz
    - tar -xvzf vale_Linux_64-bit.tar.gz
    - mv vale /usr/local/bin/
    - vale sync
    - vale --output=line docs/
  only:
    - merge_requests
From the actual .gitlab-ci.yml in Vale’s repository:
.gitlab-ci.yml
image: golang:1.25

stages:
  - test
  - release

test:
  stage: test
  script:
    - make setup
    - make build os=linux exe=vale
    - make test

With Caching

.gitlab-ci.yml
vale:
  stage: test
  image: golang:1.25
  cache:
    paths:
      - .cache/vale/
  before_script:
    - wget https://github.com/errata-ai/vale/releases/latest/download/vale_Linux_64-bit.tar.gz
    - tar -xvzf vale_Linux_64-bit.tar.gz
    - mv vale /usr/local/bin/
  script:
    - vale sync
    - vale --output=line docs/
  artifacts:
    when: always
    reports:
      codequality: vale-report.json

CircleCI

Integrate Vale into CircleCI workflows:
.circleci/config.yml
version: 2.1

jobs:
  vale:
    docker:
      - image: cimg/base:stable
    steps:
      - checkout
      - run:
          name: Install Vale
          command: |
            wget https://github.com/errata-ai/vale/releases/latest/download/vale_Linux_64-bit.tar.gz
            tar -xvzf vale_Linux_64-bit.tar.gz
            sudo mv vale /usr/local/bin/
      - run:
          name: Sync styles
          command: vale sync
      - run:
          name: Run Vale
          command: vale --output=line docs/

workflows:
  version: 2
  test:
    jobs:
      - vale

Jenkins

Integrate Vale into Jenkins pipelines:
Jenkinsfile
pipeline {
    agent any
    
    stages {
        stage('Install Vale') {
            steps {
                sh '''
                    wget https://github.com/errata-ai/vale/releases/latest/download/vale_Linux_64-bit.tar.gz
                    tar -xvzf vale_Linux_64-bit.tar.gz
                    sudo mv vale /usr/local/bin/
                '''
            }
        }
        
        stage('Lint') {
            steps {
                sh 'vale sync'
                sh 'vale --output=line docs/ > vale-output.txt || true'
                recordIssues(
                    tool: issues(
                        pattern: 'vale-output.txt',
                        name: 'Vale'
                    )
                )
            }
        }
    }
}

Pre-commit Hook

Use Vale with the pre-commit framework:
1

Create hook configuration

Add to .pre-commit-config.yaml:
.pre-commit-config.yaml
repos:
  - repo: https://github.com/errata-ai/vale
    rev: v3.0.0
    hooks:
      - id: vale
2

Install pre-commit

pip install pre-commit
pre-commit install
3

Run on commit

Vale now runs automatically on git commit:
git add docs/new-page.md
git commit -m "Add new page"
# Vale runs automatically
Vale’s .pre-commit-hooks.yaml defines the hook:
.pre-commit-hooks.yaml
- id: vale
  name: vale
  description: Run Vale on documentation
  entry: vale
  language: golang
  files: \.(md|mdx|txt|rst|adoc)$

Docker

Run Vale in a Docker container:
Dockerfile
FROM alpine:latest

RUN apk add --no-cache wget tar

WORKDIR /app

RUN wget https://github.com/errata-ai/vale/releases/latest/download/vale_Linux_64-bit.tar.gz && \
    tar -xvzf vale_Linux_64-bit.tar.gz && \
    mv vale /usr/local/bin/ && \
    rm vale_Linux_64-bit.tar.gz

COPY .vale.ini .
COPY styles/ styles/

ENTRYPOINT ["vale"]
CMD ["--help"]
Use in CI:
.github/workflows/vale.yml
jobs:
  vale:
    runs-on: ubuntu-latest
    container:
      image: myorg/vale:latest
    steps:
      - uses: actions/checkout@v3
      - run: vale docs/

Filtering Results

Control which alerts cause CI failures:

By Alert Level

# Only fail on errors
vale --minAlertLevel=error docs/

# Fail on warnings and errors
vale --minAlertLevel=warning docs/

# Report everything, but only fail on errors
vale --minAlertLevel=suggestion docs/

By Configuration

.vale.ini
MinAlertLevel = warning

[*.md]
BasedOnStyles = MyStyle

# Disable specific rules in CI
MyStyle.Pedantic = NO

# Only enable critical rules
[docs/api/**/*.md]
BasedOnStyles = MyStyle
MyStyle.Spelling = YES
MyStyle.Terms = YES

By Environment Variable

Use environment variables to change behavior in CI:
export VALE_MIN_ALERT_LEVEL=error
vale docs/
Supported environment variables (from internal/core/config.go):
  • VALE_CONFIG_PATH: Path to .vale.ini
  • VALE_STYLES_PATH: Override StylesPath
  • VALE_MIN_ALERT_LEVEL: Override MinAlertLevel
Environment variables override configuration file settings.

Handling Sync in CI

The vale sync command downloads style packages defined in Packages.

Caching Styles

Cache the styles directory to speed up CI:
.github/workflows/vale.yml
jobs:
  vale:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      
      - name: Cache Vale styles
        uses: actions/cache@v3
        with:
          path: styles/
          key: vale-styles-${{ hashFiles('.vale.ini') }}
      
      - name: Install Vale
        run: |
          wget https://github.com/errata-ai/vale/releases/latest/download/vale_Linux_64-bit.tar.gz
          tar -xvzf vale_Linux_64-bit.tar.gz
          sudo mv vale /usr/local/bin/
      
      - name: Sync styles
        run: vale sync
      
      - name: Run Vale
        run: vale docs/

Pre-downloaded Styles

Commit styles to your repository to avoid sync:
# Download styles locally
vale sync

# Commit the styles directory
git add styles/
git commit -m "Add Vale styles"
Update .vale.ini to remove Packages:
.vale.ini
StylesPath = styles
MinAlertLevel = warning

[*.md]
BasedOnStyles = Microsoft, MyStyle

Generating Reports

Create reports for CI artifacts:

JSON Report

vale --output=JSON docs/ > vale-report.json

HTML Report

Use a custom tool to convert JSON to HTML:
vale --output=JSON docs/ | python scripts/vale-to-html.py > vale-report.html

Parallel Execution

Vale automatically processes files in parallel. Control concurrency with environment variables:
# Limit to 4 concurrent files
export GOMAXPROCS=4
vale docs/

Best Practices

  1. Pin Vale version: Use specific versions for reproducible builds
  2. Cache styles: Speed up CI by caching the styles directory
  3. Use line output: Most compatible with CI error parsers
  4. Set appropriate alert levels: Only fail on errors in CI
  5. Filter by path: Run different rules on different paths
  6. Test configuration: Use vale ls-config to verify settings
  7. Handle sync properly: Either cache styles or commit them
  8. Use exit codes: Check exit code 2 for configuration errors

Troubleshooting

Configuration Not Found

Vale searches for .vale.ini in:
  1. Current directory
  2. Parent directories (up to root)
  3. $HOME/.vale.ini
Specify explicitly:
vale --config=path/to/.vale.ini docs/

Styles Not Found

Check the styles path:
vale ls-config
# Shows resolved configuration

vale ls-dirs
# Shows expected paths

Performance Issues

Optimize for large repositories:
# Process specific file types
vale --glob='*.{md,mdx}' docs/

# Exclude large files
vale --ignore='**/node_modules/**' docs/

Next Steps

Editor Integration

Set up Vale in your editor for real-time feedback

CLI Reference

Explore all CLI commands and options

Build docs developers (and LLMs) love