composer/semver: PHP version constraints without pulling in Composer
Semantic versioning utilities with the addition of version constraints parsing and checking.
At a glance
- What is it?
- The version comparison and constraint engine extracted from Composer, now a standalone MIT-licensed PHP library. It is the right dependency when you need to evaluate a constraint string like ^1.2 in your own code, and the wrong one when you want a full package manager.
- Who is it for?
- Adopt composer/semver if you are writing PHP that has to decide whether a version string satisfies something like ^1.2 or >=1.0 <2.0, and you would rather not reimplement version_compare edge cases. Do not adopt it if you need a package manager, a lock file, or non-PHP version handling: it is a comparison and parsing library and nothing more.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 6 days ago.
- What is it written in?
- Mainly PHP, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The problem composer/semver solves, and who has it
PHP ships version_compare, which compares two version strings and nothing else. It cannot answer the question most applications actually have: does this version satisfy this constraint? That question shows up in plugin systems that declare compatibility ranges, in update checkers that compare an installed version against a manifest, in package registries that validate submitted constraints, and in build tooling that decides whether a dependency bump is allowed.
composer/semver is the library that answers it. The README describes it as a "version comparison library that offers utilities, version constraint parsing and validation," originally written inside composer/composer and later extracted as a standalone package. The audience is PHP developers building something that consumes version strings, not developers who want to install packages. If you are already using Composer, you have this library on disk as a transitive dependency; adding it explicitly only matters when your own code calls it.
How constraint parsing and comparison actually work
The library is split across four classes, each with a narrow job. VersionParser turns strings into normalized versions and constraint objects. Comparator answers boolean questions about two versions. Semver filters and sorts collections of versions against a constraint. Intervals works on the parsed constraint tree itself.
The normalization step is the part that surprises people. According to the README, numeric versions are normalized to four components, so 1.2.3 becomes 1.2.3.0. The stated reason is internal consistency and compatibility with version_compare. The README also states plainly that normalized versions should not be shown to end users, which tells you the format is an implementation detail leaking through a public method. Constraints are parsed into ConstraintInterface objects, and Intervals::get() converts one of those into an array of numeric intervals and branch constraints.
The README is candid about the fidelity limit: the library follows semver where possible but is "constrained by version_compare and backwards compatibility and as such cannot implement semver strictly." That sentence is the most important one on the page. If your project needs strict SemVer 2.0 ordering, particularly around pre-release precedence, you should read the Versions article on getcomposer.org before assuming this library matches the specification.
Installing composer/semver and checking your first constraint
Installation is a single Composer command, and the README gives it directly:
composer require composer/semverThe README lists PHP 5.3.2 as the minimum requirement and recommends the latest PHP version. After the command completes, the package is available under the Composer\Semver namespace with no configuration and no service provider registration.
The smallest useful thing you can do is ask whether one version satisfies a constraint. The README's Semver class exposes satisfies($version, $constraints) for exactly this, and the README's own example of the Comparator class shows the shape of a call:
use Composer\Semver\Comparator;
Comparator::greaterThan('1.25.0', '1.24.0'); // 1.25.0 > 1.24.0That call returns a boolean. Constraint strings are parsed as they are used, so if you are evaluating the same constraint against many versions, parse it once and reuse it rather than re-parsing inside a loop.
If you need to filter or sort a list, Semver::satisfiedBy(array $versions, $constraint) and Semver::sort($versions) handle that without you writing a comparison callback.
The Intervals class and its memoization cache
Intervals is the least obvious part of the public API and the one most likely to cause trouble in a long-running process. It provides isSubsetOf, haveIntersections, compactConstraint, get, and clear. The README notes that haveIntersections is equivalent to calling matches on one constraint with the other, so it exists for readability as much as capability.
compactConstraint is where the trade-offs are explicit. The README says it merges all intervals down to the smallest possible multi constraint, and then names two drawbacks: it is not very fast, and the resulting multi constraint has no human readable prettyConstraint configured on it. That second point matters if you were planning to echo the constraint back to a user after compacting it. You would be printing something with no pretty form.
The clear method is the one to remember. The README describes it as clearing the memoization cache "when you are done processing constraints." A memoization cache that is never cleared is a memory leak in a queue worker or a long-lived server process. If your code path touches Intervals repeatedly across jobs, call Intervals::clear() at the end of the batch.
Where composer/semver is the wrong tool
It is not a package manager and will not resolve dependencies. It parses and compares constraints; it does not fetch metadata, build a dependency graph, or pick a version set. If that is what you need, you need Composer itself.
It is also PHP-only. The API is a set of PHP classes, and there is no CLI, no server, and no language binding in the repository layout. Projects in other languages should look at their own ecosystem's implementation rather than trying to shell out to this one.
The strictness caveat deserves repeating because it is easy to miss. The README says the library cannot implement semver strictly, because of version_compare and backwards compatibility. That is a deliberate choice inherited from Composer's history, not an oversight. If you are validating that a third party's version string conforms to SemVer 2.0, this library will accept and normalize inputs that a strict parser might reject, and its ordering of pre-release identifiers may not match the specification. The README points to the getcomposer.org Versions article for the details, and that article, not this README, is where you should check before relying on edge-case ordering.
Finally, the README does not document rollback, deprecation policy, or a migration guide between major versions. The CHANGELOG.md file exists at the repository root, but the README itself is silent on upgrade paths.
Alternatives and the difference in approach
The obvious alternative is not using a library at all and calling PHP's version_compare directly. That works for simple ordering and costs nothing, but it gives you no constraint language. You would have to write your own parser for caret, tilde, wildcard, and range syntax, plus the hyphen ranges Composer supports. That is the exact work this library already did.
In other ecosystems, the equivalent role is played by packages like node-semver in JavaScript and the packaging library's specifiers in Python. The approaches differ in what they treat as the source of truth. This library normalizes everything to four numeric components so that version_compare can do the heavy lifting, which is why the README warns against showing normalized versions to users. A strict SemVer implementation would keep the three-component form and handle pre-release precedence itself. Neither is wrong, but they will disagree on unusual inputs.
A second alternative is depending on composer/composer and reaching into its internals. That pulls in the entire package manager for one utility. The README states the extraction from composer/composer happened precisely so the library could stand alone, so taking the smaller dependency is the intended path.
Maintenance, licence, and what upgrading costs
The repository is not archived and the last push was on 2026-09-01. Recent releases are 3.4.4 on 2025-08-20, 3.4.3 on 2024-09-19, and 3.4.2 on 2024-07-12. The version numbers tell you the project is on a 3.x line with patch releases, so the API surface is stable and you should not expect breaking changes without a major bump. The gaps between releases are long, which is normal for a library whose behaviour is tied to a specification Composer already depends on.
composer/semver is licensed under the MIT License, with the LICENSE file at the repository root. MIT is permissive: it allows use in closed-source products, modification, and redistribution, provided the copyright notice and permission notice are retained. That is a summary of the licence text, not legal advice; read the LICENSE file and talk to counsel if your organisation has specific requirements. The practical implication is that there is no copyleft obligation attached to shipping this library inside a proprietary application.
The upgrade cost is low for patch releases within 3.x. Since the README does not document a migration path, check CHANGELOG.md at the repository root before moving between minor versions, and pin the version in composer.json if you want releases to arrive on your schedule rather than during a routine composer update.
Editorial conclusion
Adopt composer/semver if you are writing PHP that has to decide whether a version string satisfies something like ^1.2 or >=1.0 <2.0, and you would rather not reimplement version_compare edge cases. Do not adopt it if you need a package manager, a lock file, or non-PHP version handling: it is a comparison and parsing library and nothing more. Before you commit, verify two things in your own codebase: that your callers never display normalized versions to users, since numeric versions become four components, and that you call Intervals::clear() in long-running workers after a batch of constraint work.
Frequently asked questions
What does SemVer mean?
SemVer is semantic versioning, the MAJOR.MINOR.PATCH scheme. The composer/semver README notes that the library follows semver where possible but cannot implement it strictly because of version_compare and backwards compatibility.
What is a SemVer range?
A range is a constraint expression that a version may or may not satisfy. composer/semver parses these constraint strings into ConstraintInterface objects through VersionParser::parseConstraints.
How do I install composer/semver?
Run composer require composer/semver, as shown in the README's Installation section. The README lists PHP 5.3.2 as the minimum requirement and recommends using the latest PHP version.
How do I use composer/semver to check a version against a constraint?
Call Semver::satisfies($version, $constraints), which returns a boolean, or use the Comparator class methods such as greaterThan for two-version comparisons. Both are documented in the README's Basic usage section.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/composer-semver)