PURL Components

A Package URL (PURL) is a URL string used to identify and locate a software package in a mostly universal and uniform way across programming languages, package managers, and packaging conventions.

PURL Format

A PURL follows this format:

pkg:type[/namespace]/name[@version][?qualifiers][#subpath]

Components

ComponentRequiredDescriptionExample
typeYesPackage ecosystemjulia, npm, pypi, maven
namespaceNoOrganizational grouping@angular (npm), org.apache (maven)
nameYesPackage nameExample, lodash
versionNoPackage version1.0.0, 4.17.21
qualifiersNoKey-value metadataarch=x86_64, os=linux
subpathNoPath within packagelib/core

Accessing Components

using PackageURLs

purl = parse(PURL, "pkg:maven/org.apache.commons/commons-lang3@3.12.0?classifier=sources")

purl.type       # "maven"
purl.namespace  # "org.apache.commons"
purl.name       # "commons-lang3"
purl.version    # "3.12.0"
purl.qualifiers # Dict("classifier" => "sources")
purl.subpath    # nothing

Supported Package Types

PackageURLs.jl supports all standard PURL types, including:

TypeEcosystemNotes
juliaJulia packagesRequires uuid qualifier
npmNode.js packagesSupports scoped packages (@scope/name)
pypiPython packagesName normalized to lowercase
mavenJava/Maven packagesNamespace is the group ID
nuget.NET packages
cargoRust packages
gemRuby gems
golangGo modules
githubGitHub repositories
bitbucketBitbucket repositories
dockerDocker images
genericFallback for any package

Type-Specific Rules

Julia

Julia PURLs require the uuid qualifier for package disambiguation. This is because multiple packages can have the same name in different registries.

# Valid Julia PURL
purl"pkg:julia/Example@1.0.0?uuid=7876af07-990d-54b4-ab0e-23690620f79a"

# Invalid - missing uuid qualifier
parse(PURL, "pkg:julia/Example@1.0.0")  # Throws PURLError

The UUID can be found in the package's Project.toml file or in the Julia General registry.

PyPI

PyPI package names are normalized to lowercase, with underscores converted to hyphens:

# These all refer to the same package
parse(PURL, "pkg:pypi/Django@4.0").name      # "django"
parse(PURL, "pkg:pypi/DJANGO@4.0").name      # "django"
parse(PURL, "pkg:pypi/some_package").name    # "some-package"

npm

npm supports scoped packages with the @scope/name format. The @ must be percent-encoded as %40:

# Scoped package
purl"pkg:npm/%40angular/core@15.0.0"

# Unscoped package
purl"pkg:npm/lodash@4.17.21"

Maven

Maven PURLs use the namespace for the group ID:

purl"pkg:maven/org.apache.commons/commons-lang3@3.12.0"
# namespace: "org.apache.commons"
# name: "commons-lang3"