SemVer range satisfies checker
Package upgrades often depend on a deceptively small question: does one exact semantic version belong to the range written in a manifest, lockfile rule, release policy, or compatibility matrix?
Run — free
This checker evaluates that question with deterministic SemVer precedence. It understands comparison operators, whitespace intersections, hyphen ranges, wildcard and partial versions, and double-pipe alternatives. Prerelease and build identifiers receive their proper semantic meaning, so the result is suitable for dependency tooling rather than a rough numeric comparison.
Write a version and the range you need to test
Provide one complete semantic version such as <code>2.4.1</code> and one range expression. A whitespace-separated comparator set means every comparator must pass, so <code>>=2.0.0 <3.0.0</code> accepts stable releases from major version two. Separate sets with <code>||</code> when either branch may pass. An exact version is also a valid range. The checker returns the normalized version, the trimmed range, a boolean result, and the one-based alternative that matched; zero means no alternative matched. This explicit result shape makes the capability easy to place in a deployment guard, dependency report, manifest editor, or test fixture without parsing prose. Inputs are deliberately strings because converting versions to floating-point numbers would make 1.10 appear smaller than 1.9 and would discard prerelease information. A leading <code>v</code> on a complete version is accepted and normalized away, while malformed numeric components, empty alternatives, and invalid identifiers produce a typed input error instead of an unreliable false result.
Use comparators, hyphen ranges, and wildcards precisely
Comparators may use <code>></code>, <code>>=</code>, <code><</code>, <code><=</code>, or <code>=</code>. Multiple comparators in one alternative form an intersection. A hyphen expression such as <code>1.2.3 - 2.4.0</code> includes both complete endpoints, while a partial upper endpoint expands to the end of that component family: <code>1.2 - 2.4</code> begins at 1.2.0 and stops before 2.5.0. Wildcards may be written as <code>x</code>, <code>X</code>, or <code>*</code>. Thus <code>3.x</code> covers stable 3.0.0 through versions below 4.0.0, and the partial range <code>3.2</code> behaves like <code>3.2.x</code>. Wildcards must trail known components; an expression such as <code>1.x.4</code> is rejected because it does not describe a coherent interval. Caret and tilde shorthand are intentionally rejected by this capability. Express those boundaries with explicit comparators so the evaluated rule remains visible and unambiguous in logs, generated policies, automated checks, and human reviews.
Understand precedence, prereleases, and build metadata
Semantic versions are compared component by component, not alphabetically. Major, minor, and patch numbers decide first. A prerelease has lower precedence than the corresponding stable release, and its dot-separated identifiers are compared from left to right: numeric identifiers compare numerically, numeric identifiers sort before nonnumeric ones, and a shorter equal prefix sorts first. Build metadata after <code>+</code> is preserved in the normalized output but never changes precedence, as required by SemVer. Dependency managers also protect users from accidentally selecting prereleases. This checker follows that behavior: a prerelease can satisfy a comparator set only when that same set contains a prerelease comparator with the identical major, minor, and patch tuple. For example, <code>2.0.0-beta.2</code> may satisfy <code>>=2.0.0-beta.1 <2.0.0</code>, but it does not enter a broad wildcard merely because its numeric core fits. Every evaluation is local and deterministic. No registry is queried, no package is downloaded, and no current release is guessed, so repeated calls with the same strings return the same decision.
What you can do with it
Validate dependency candidates
Check a proposed package version against the range declared by a consuming project before changing a lockfile.
Guard a release pipeline
Permit or reject deployment artifacts according to an explicit compatibility window stored in release policy.
Explain manifest behavior
Test boundary, wildcard, alternative, and prerelease cases while debugging why a resolver accepts or skips a release.
FAQ
What does one check cost through the API?
Each request costs $0.002. The same deterministic checker can also run directly in the browser.
Can a range contain multiple conditions?
Yes. Separate AND conditions with whitespace and OR alternatives with ||.
Are hyphen range endpoints inclusive?
Complete endpoints are inclusive. A partial upper endpoint expands to an exclusive boundary above its component family.
Does build metadata affect the result?
No. Build metadata is preserved in the normalized version but ignored for SemVer precedence.
Why did a prerelease fail a broad range?
A prerelease is eligible only when its comparator set explicitly includes a prerelease with the same major, minor, and patch values.
Are caret and tilde ranges supported?
No. Use explicit comparators, hyphen ranges, wildcards, partial versions, or || alternatives.
For developers — API access
Everything on this page is available programmatically. This section is for teams who want to wire it into their own systems; everyone else can just use the tool above.
API endpoint
Prefer to automate it? One authenticated POST creates the task; the result comes back by webhook or a signed link. The same capability also runs here on the web, by email and from Telegram — and soon from our app too.
Call it from your stack
curl -X POST https://api.kit.forhosting.com/dev/semver-satisfies \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"version":"2.4.1","range":">=2.0.0 <3.0.0"}'const res = await fetch("https://api.kit.forhosting.com/dev/semver-satisfies", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"version": "2.4.1",
"range": ">=2.0.0 <3.0.0"
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/dev/semver-satisfies",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"version": "2.4.1",
"range": ">=2.0.0 <3.0.0"
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/dev/semver-satisfies", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"version":"2.4.1","range":">=2.0.0 <3.0.0"}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"version":"2.4.1","range":">=2.0.0 <3.0.0"}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/dev/semver-satisfies", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Example request
{
"version": "2.4.1",
"range": ">=2.0.0 <3.0.0"
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "dev.semver_satisfies",
"status": "queued",
"_links": {
"result": "/tasks/tsk_…/result"
}
}The API is asynchronous: the call returns a task_id immediately and the result arrives by webhook. Polling is capped at 1 req/s per task.
Pricing
Published price — no tokens, no invented credits. A failed task is never charged.
Errors
| HTTP | Code | Meaning |
|---|---|---|
401 | unauthorized | Missing or invalid API key. |
402 | insufficient_balance | Your balance doesn't cover the task price. |
404 | unknown_type | That task type doesn't exist. |
429 | rate_limited | Too many requests. Use the webhook instead of polling. |