A purl, short for Package URL, is a standardized, URL-style identifier for a software package that works across ecosystems and distribution channels. It gives tools one consistent way to say "this exact package," whether it comes from npm, Maven, PyPI or elsewhere.
The structure
The purl specification gives the shape as scheme, type, namespace, name, version, qualifiers and subpath:
scheme:type/namespace/name@version?qualifiers#subpath
- scheme is always
pkg - type is the package manager or ecosystem, such as
npm,mavenorpypi(required) - namespace is an optional prefix, such as a Maven group ID or a GitHub owner, and its meaning depends on the type
- name is the package name (required)
- version is optional
- qualifiers are optional type-specific key and value pairs, such as architecture or repository
- subpath is an optional path inside the package
A worked example
The specification's example is pkg:npm/%40angular/animation@12.3.1. It identifies version 12.3.1 of the npm package animation in the @angular namespace. The %40 is an encoded @ character.
Reading a purl left to right tells you the ecosystem first, which matters because the same name can exist in more than one registry and mean different things.
Why SBOM and scanning tools care
Matching a component to a vulnerability record is harder than it sounds. Names differ between ecosystems, and free-text names invite mistakes. A purl removes ambiguity, so an SBOM entry, a vulnerability feed and a license database can all point at the same thing.
Formats like CycloneDX and SPDX can carry a purl on each component. Check that your tools actually fill it in.
Tips for using them
- Include the version. A purl without one identifies a package, not a release, and vulnerabilities are tied to releases.
- Keep the ecosystem type accurate. A wrong type produces false matches or missed ones.
- Encode special characters, as the example does for
@. - Compare purls as whole strings after normalizing, instead of hand parsing them with regular expressions.
Safeguard's dependency scanning identifies components by ecosystem and version. A free scan is at gold.safeguard.sh/scan.
Quick check
Is a purl a download link?
No. It looks like a URL but identifies a package. It does not say where to fetch it, though a repository qualifier can hint at that.
Which parts of a purl are required?
The type and the name. The scheme is always pkg, and the rest is optional.
Sources
Last reviewed: 19 October 2026.