Tilde is usually the tighter of the two for applications, and caret is the Composer recommendation for libraries. Caret ^1.2.3 allows up to but not including 2.0.0. Tilde ~1.2.3 allows up to but not including 1.3.0. Whichever you pick, avoid unbounded ranges.
What each operator allows
| Constraint | Means | Allows |
|---|---|---|
| 1.0.2 | Exact version | Only that version |
| ^1.2.3 | Caret | 1.2.3 up to below 2.0.0 |
| ^0.3 | Caret on 0.x | 0.3.0 up to below 0.4.0 |
| ~1.2 | Tilde | 1.2 up to below 2.0.0 |
| ~1.2.3 | Tilde with patch | 1.2.3 up to below 1.3.0 |
| 1.0.* | Wildcard | 1.0 up to below 1.1 |
| >=1.0 | Unbounded | Any future version, including breaking ones |
The Composer docs call the caret operator the recommended one for maximum interoperability when writing library code. For 0.x versions it is stricter, because semantic versioning treats those as unstable.
Why unbounded ranges are a supply chain risk
A constraint like >=3.4 or * accepts any future major release. The Composer FAQ points out that once a version is tagged, its dependencies cannot be changed, so a broken release stays broken. The security view is similar: an open ended range gives a new owner of a package, or an attacker who gets in, a path into every project that did not set an upper bound. A lock file softens this for applications, but not for the next person who runs update.
How to choose
- For an application, prefer constraints that match how much change you will review. Tilde with a patch number is tight. Caret is looser.
- For a library, use caret so your users can resolve against other packages.
- Never use an open ended range for a package you do not control.
- Avoid dev branches as constraints in anything that deploys.
- Rely on composer.lock for exact versions, and treat constraints as the policy for what update may pick.
composer require vendor/package:^2.4
composer outdated --direct
A practical habit
Constraints say what is allowed. The lock file says what is installed. When you bump a constraint, read the lock diff. A wide constraint plus a casual composer update is how a surprise reaches production.
Try it yourself
Click through it at your own pace, or open it full screen. See how a constraint decides whether a patched version can be taken.
Where Safeguard fits
Safeguard's SBOM and dependency scanning reads composer.lock and Gemfile.lock and flags known advisories. A free scan takes a few minutes.
Quick check
Is caret or tilde riskier?
Caret generally allows more change, since it spans to the next major. Tilde with a patch number allows less.
Do constraints matter if I have a lock file?
Yes. They decide what composer update can choose the next time it runs.
Sources
Last reviewed: 19 October 2026.