Alternatives to PVP for Alpha / Exploratory packages?

Trying to develop an alpha / exploratory lib, I’ve found that PVP is a complete pain in the ass because it implies that I have to completely solidify the API while I’m still intending a package for testing purposes.

If I want to completely refactor the package and change the API, or do some major changes, I can’t, because it’ll bump up my version numbers tremendously.

Are there any alternatives to PVP for “screwing around packages” that don’t involve putting it up on Github / Codeberg? If we’re talking Github or Codeberg, even then it’d be useful to have an alt-PVP for messing around.


Hackage has candidates: Uploading packages and package candidates | Hackage

If you have suggestions for changing PVP, you can write a proposal: Issues · haskell/pvp · GitHub

Keep in mind that it would be a new version of the spec and likely have to be very well thought through to even get a chance to be remotely accepted.


What you are looking for is probably something like §4 of the SemVer specification: Semantic Versioning 2.0.0 | Semantic Versioning

  1. Major version zero (0.y.z) is for initial development. Anything MAY change at any time. The public API SHOULD NOT be considered stable.

The PVP spec that Hackage follows is older than SemVer, and doesn’t provide a similar clause, sadly.


What’s wrong with bumping the version numbers tremendously? In fact, you’re going to bump your version numbers tremendously either way (once for each release) it’s just a question of which component you bump. Why is it a problem to bump x tremendously but not y, in w.x.y.z?


I’d rather reserve w for total rewrites of API, and naively, I’d assume a 0.x version is a prototype, while a 1 version is finished to some degree.

Implicitly, with your suggestion, I’d end up publishing, which to the outside user implies that it’s much more mature than it is.

With my suggestion you’d end up with, which seems exactly what you want, unless I’m somehow missing something …


You don’t need to take version numbers seriously until you actually release your package, you know. While it’s in an exploratory stage, you can just keep it at 0.1.0, even with PVP, and if you have other code that depends on it, just pull it in from git (doesn’t have to be github, you can host your git repo anywhere cabal can find it), and use commit hashes to pin your dependencies to an exact version.

Once you release it, bump the version number; you can still be as experimental as you want on the git version, you just need to bump the version number correctly when you make the next (Hackage) release, and you only need to worry about the current release and the previous one when determining the correct PVP version number. The in-between “experimental” versions may not have the correct version number, but that’s OK, because you’re not releasing them into the Hackage / Cabal ecosystem, so they will never be selected by the Cabal solver unless you explicitly ask for them (via, again, a git repo dependency, which you should pin to an exact commit hash).


That’s actually a rather confusing part of semver. It doesn’t exactly define what “stable” means. If my API is unstable, can I release breaking changes under a patch version increment? It doesn’t say. If not, what information does section 4 even convey?

Some libraries go through “unstable” API phases late in their lifetime.


But candidates can’t be added as deps, can they?

I think you can add a tarball URL, but then the URL would point to a mutable source, and that is problematic.

The problem with the solution, is, well: bytestring, which I think most people consider stable and mature, is on,

I guess it’s pretty presumptuous of me, but it seems as though it might be viable to amend PVP and the system surrounding it; i.e, allow a single-digit alphanumeric character in the PVP version code.

X could stand for experimental (quickly changing API), U could stand for “unmaintained”, i.e, it’s finished on fork-it-or-leave-it support, and other particular codes for “unusual” package versioning states.

Ah, I see. So you don’t just want a policy that you can apply to your own packages, but you want a policy that’s shared between all Haskell packages? The latter’s much harder of course!

Well, it’s just idle speculation; I have lots of that if that’s what you’re looking for.

FWIW You can depend directly on git repos in cabal.project or stack.yaml. So if it’s just exploratory for use in another project you control, you could not publish at all and just depend on the git repo at a commit


Hackage is a permanent storage, one should not release stuff there just to experiment on. As @brandonchinn178 suggests, use cabal.project / stack.yaml to specify dependencies via Git repository.

That said, you can version a package as 0.20230901, 0.20230918, 0.20231001, etc. This way you comply with PVP fully, but also do not make a false impression of being well-established.


Perennial reminder that, for better or worse, PVP treats 0.x as a major version. (Bad for optics in my opinion, and cause of considerable confusion given the extremely wide spread of SemVer at this point in history.)


It might be worth pointing out that SemVer main innovation was to remove from version numbers any meaning other than API compatibility. I.e. the only “semantic” is whether a new version change the API. Following this approach, there’s nothing “major” about a major bump; perhaps we should try to avoid the major/minor terminology.

Does anybody remember the romantic and the sentimental versioning comebacks? :relaxed:

1 Like