PMD is an open-source static analysis tool that scans source code for common programming flaws, including potential bugs, dead code, suboptimal code, and security vulnerabilities.
With over 5,300 GitHub stars, 312 contributors, and more than 30,000 commits, PMD represents one of the most mature and actively maintained code analysis projects in the Java ecosystem.
Originally created for Java, PMD now supports multiple languages and includes CPD (Copy/Paste Detector), a tool for finding duplicated code across large codebases.
What is PMD?
PMD analyzes source code without executing it, applying configurable rules to identify problematic patterns.
The tool earned its reputation in the Java community for catching issues that compilers miss but that lead to bugs, maintainability problems, or security vulnerabilities in production.
The name PMD does not officially stand for anything, though the community has proposed various backronyms including “Programming Mistake Detector” and “Pretty Much Done.” What matters is its effectiveness: PMD ships with over 400 built-in rules covering code style, design issues, potential bugs, and security concerns.
PMD is used by Salesforce’s Code Analyzer for Apex development, making it the de facto standard for Salesforce security and code quality analysis.
The tool also integrates with SonarQube and other code quality platforms, serving as a rule engine within larger analysis workflows.
Key Features
Comprehensive Rule Library
PMD includes hundreds of rules organized by category:
- Best Practices: Identifies code that works but could be written better
- Code Style: Enforces consistent formatting and naming conventions
- Design: Detects structural issues like excessive class complexity
- Documentation: Checks for missing or inadequate comments
- Error Prone: Catches patterns that commonly lead to bugs
- Performance: Identifies inefficient code patterns
- Security: Detects potential security vulnerabilities
Rules can be enabled or disabled individually, and severity levels can be customized to match organizational standards.
Copy/Paste Detector (CPD)
CPD finds duplicated code across files and even across different languages.
Code duplication is a significant maintainability concern because bugs fixed in one location often remain unfixed in copies.
CPD supports:
- Java, C/C++, C#, Go, Kotlin, Ruby, Swift, and many more
- Configurable minimum token threshold
- Ignoring comments and literals
- Multiple output formats for integration
Custom Rule Development
PMD allows creating custom rules through multiple approaches:
- XPath rules: Write rules using XPath expressions against the AST (Abstract Syntax Tree)
- Java rules: Implement complex logic in Java for sophisticated analysis
- Rule references: Compose rules from existing rules with modified properties
This extensibility allows organizations to encode their specific coding standards into automated checks.
Incremental Analysis
For large codebases, PMD supports incremental analysis that only processes changed files.
This dramatically reduces analysis time in CI/CD pipelines where most builds only modify a few files.
Installation
Command Line Installation
# Download latest release
curl -LO https://github.com/pmd/pmd/releases/download/pmd_releases%2F7.21.0/pmd-dist-7.21.0-bin.zip
unzip pmd-dist-7.21.0-bin.zip
cd pmd-bin-7.21.0
# Add to PATH (bash/zsh)
export PATH=$PATH:$(pwd)/bin
# Verify installation
pmd --version
Package Managers
# macOS via Homebrew
brew install pmd
# Linux via SDKMAN
sdk install pmd
Running PMD
# Basic analysis
pmd check -d /path/to/source -R rulesets/java/quickstart.xml -f text
# With specific ruleset
pmd check \
--dir ./src/main/java \
--rulesets rulesets/java/quickstart.xml,category/java/security.xml \
--format html \
--report-file pmd-report.html
# Using CPD for duplicate detection
pmd cpd \
--dir ./src \
--minimum-tokens 100 \
--language java \
--format xml > cpd-report.xml
# Incremental analysis with cache
pmd check \
--dir ./src \
--rulesets rulesets/java/quickstart.xml \
--cache pmd-cache.bin
Maven Integration
<!-- pom.xml -->
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-pmd-plugin</artifactId>
<version>3.21.0</version>
<configuration>
<rulesets>
<ruleset>/rulesets/java/quickstart.xml</ruleset>
<ruleset>/category/java/security.xml</ruleset>
</rulesets>
<failOnViolation>true</failOnViolation>
<printFailingErrors>true</printFailingErrors>
</configuration>
<executions>
<execution>
<goals>
<goal>check</goal>
<goal>cpd-check</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
# Run PMD via Maven
mvn pmd:check
mvn pmd:cpd-check
Gradle Integration
// build.gradle
plugins {
id 'pmd'
}
pmd {
toolVersion = '7.21.0'
consoleOutput = true
ruleSetFiles = files('config/pmd/ruleset.xml')
ruleSets = [] // Disable default rulesets
}
tasks.withType(Pmd) {
reports {
xml.required = true
html.required = true
}
}
# Run PMD via Gradle
./gradlew pmdMain pmdTest
Integration
GitHub Actions
name: PMD Analysis
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
pmd:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup PMD
run: |
curl -LO https://github.com/pmd/pmd/releases/download/pmd_releases%2F7.21.0/pmd-dist-7.21.0-bin.zip
unzip pmd-dist-7.21.0-bin.zip
- name: Run PMD
run: |
./pmd-bin-7.21.0/bin/pmd check \
--dir ./src \
--rulesets rulesets/java/quickstart.xml \
--format sarif \
--report-file pmd-results.sarif
- name: Upload SARIF results
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: pmd-results.sarif
- name: Run CPD
run: |
./pmd-bin-7.21.0/bin/pmd cpd \
--dir ./src \
--minimum-tokens 100 \
--language java \
--format text
GitLab CI
stages:
- analysis
pmd:
stage: analysis
image: openjdk:17-jdk
before_script:
- apt-get update && apt-get install -y curl unzip
- curl -LO https://github.com/pmd/pmd/releases/download/pmd_releases%2F7.21.0/pmd-dist-7.21.0-bin.zip
- unzip pmd-dist-7.21.0-bin.zip
script:
- ./pmd-bin-7.21.0/bin/pmd check
--dir ./src
--rulesets rulesets/java/quickstart.xml
--format xml
--report-file pmd-report.xml
artifacts:
reports:
codequality: pmd-report.xml
paths:
- pmd-report.xml
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_COMMIT_BRANCH == "main"
Custom Ruleset
Create a custom ruleset to encode your organization’s standards:
<?xml version="1.0"?>
<ruleset name="Custom Rules"
xmlns="http://pmd.sourceforge.net/ruleset/2.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0
https://pmd.sourceforge.io/ruleset_2_0_0.xsd">
<description>Custom PMD ruleset for our project</description>
<!-- Include security rules -->
<rule ref="category/java/security.xml"/>
<!-- Include specific best practices -->
<rule ref="category/java/bestpractices.xml/AvoidReassigningParameters"/>
<rule ref="category/java/bestpractices.xml/UnusedPrivateField"/>
<!-- Customize rule properties -->
<rule ref="category/java/design.xml/CyclomaticComplexity">
<properties>
<property name="classReportLevel" value="80"/>
<property name="methodReportLevel" value="15"/>
</properties>
</rule>
<!-- Exclude specific rules -->
<rule ref="category/java/codestyle.xml">
<exclude name="AtLeastOneConstructor"/>
<exclude name="OnlyOneReturn"/>
</rule>
</ruleset>
When to Use PMD
PMD is an excellent choice for:
- Java projects seeking comprehensive code quality and security analysis without licensing costs
- Salesforce development where PMD powers the official Code Analyzer for Apex
- Teams needing duplicate detection across large codebases with CPD
- Organizations building custom rules who need extensibility through XPath or Java
- CI/CD pipelines that benefit from incremental analysis and fast execution
PMD may be less suitable when deep security analysis is the primary goal (consider Semgrep, CodeQL, or commercial SAST tools), when analyzing languages not well-supported by PMD, or when a managed SaaS experience is preferred over self-hosted tooling.
PMD works well alongside other tools in a defense-in-depth strategy.
Many teams run PMD for code quality and style, then layer specialized security scanners for vulnerability detection.