macsAirMELPA is the original and independent Emacs Lisp package archive.
A few days ago we have published two new MELPA channels, MELPA Snapshots and MELPA Releases. For now these channels are considered experimental and coexist with the traditional channels MELPA (“regular” a.k.a. “unstable”) and MELPA Stable. Eventually the snapshots channel is going to replace unstable, and releases is going to replace stable. But don’t worry, if you are not ready to update just yet; the new channels are still considered experimental and the current thinking is that they won’t replace the traditional channels for around another year.
After years in the making, MELPA is finally moving away from using
raw timestamps as version strings for development versions. While
the traditional unstable channel uses the version string format
YYYYMMDD.HHMM, the new snapshots channel uses
RELEASE.0.YYYYMMDD.COUNT.
RELEASE is the latest release, i.e., the version distributed on the
releases channel. YYYYMMDD is the committer date. Instead of
appending the time to the date, COUNT is used; the number of commits
since the latest release (i.e., RELEASE).
If no release information can be determined, then 0.0 is used as
RELEASE and COUNT is the number of commits since the initial
commit.
If no new commits since that release touch any files, that are
included in the package tarball, then the same release is distributed
on the snapshots channel as well; build from the same commit and
using the same RELEASE version string as on the releases channel.
That’s all wonderful, but just take me to the setup instructions.
The main advantage of not using raw timestamps as version strings for
snapshots is, that a snapshot version will no longer be greater than
every release. That was a problem because it meant that any
snapshot seemingly satisfied the minimal dependency on even the very
latest release of a dependency. E.g., org-20040101.1234 is
considered greater than org-9.8.6, by version<. The new snapshot
version strings do not have this issue:
1.2.3 < 1.2.3.0.20260701.4 < 1.2.4
Instead of just ., we inject .0. in between the RELEASE and
DATE. We do that to allow package maintainers to add one version
string component when creating a new release, without throwing the
just mentioned improvement out of the window again. I.e., 2.0 <
2.0.0.20260701.4 < 2.0.1.
Well, when that was first proposed, I mentioned that it has a definite “designed by committee” feel to it, but I considered it a good compromise and have come to actually like it.
I would have liked to use just COUNT because it is shorter and IMO
encodes more useful information than DATE.TIME. That being said,
both DATE and COUNT are useful information, and so it makes sense
to encode both in the version string.
A few weeks ago GNU-devel ELPA and NonGNU-devel ELPA also switched
to the RELEASE.0.DATE.COUNT format. Version string compatibility
between different ELPA is important, so I finally gave up on the
RELEASE.0.COUNT idea, and returned my focus to getting some sane
format across the finish line.
Until now, MELPA exclusively used git/mercurial tags to determine the
latest release and the commit corresponding to it, while (Non)GNU ELPA
exclusively use the Version or Package-Version library header.
Neither of these approaches is compatible with reality. Many maintainers use only tags, while many other maintainers use only the library header. To detect the latest release for most packages (that actually do releases), a package archive has to consult both potential sources of versioning truth.
For the new releases and snapshots channels we first consult the tags, and iff there are no release tags, then we fall back to the library header.
Because it considers both version information sources and also falls
back to using the 0.0 stand-in, if both version sources are void,
the releases channel features 6207 packages, compared to
stable’s 3400. (The reason why it doesn’t feature all 6240
packages, available from the unstable and snapshots channels,
is that the latest releases of these 33 packages are defective.)
I should expand on this in a separate post, but the gist is this:
Make sure you tag exactly the commit that bumps the Version
library header with the corresponding release tag. This way, and
only this way, the same commit will be considered to be release N,
regardless of whether some tool looks at the header or the tag, and
regardless of how it deals with conflicting information, if it
supports both sources.
If you forget to create (or push) a tag, that is not a huge issues; once you notice, just tag the commit that bumped the header. If you create a tag but forgot to bump the header, then that release is broken and cannot be fixes, and you must create a new, greater release.
You do not want to end up in this situation:
ddddddd Ups, also bump version header # 1.2.0 on GNU ELPA - ;; Version: 1.1.0 + ;; Version: 1.2.0 ccccccc Massive refactoring bbbbbbb Totally harmless change aaaaaaa (tag: v1.2.0) Release 1.2.0 # 1.2.0 on MELPA
If you did that, and a user reports an issue and mentions that they are using "1.2.0", you won't immediately know which "1.2.0" and thus whether this is a regression in "totally harmless change" or "massive refactoring", or a long-standing issue that has so far gone unnoticed.
Also don't do this:
zzzzzzz (tag: v2.0.0) Release 2.0.0 # 2.0.0 on MELPA ... many commits ... bbbbbbb Begin work toward 2.0.0 # 2.0.0 on GNU ELPA - ;; Version: 1.2.0 + ;; Version: 2.0.0 aaaaaaa (tag: v1.2.0) Release 1.2.0
You might think this is obvious, but unfortunately there is a large number of packages, for which the two sources of versioning truth do not agree.
Make sure you don’t stop after the first step!
To switch from “regular” MELPA to the new snapshots channel, locate a setting like this in your configuration
(add-to-list 'package-archives
'("melpa" . "https://melpa.org/packages/") t)
and replace it with
(add-to-list 'package-archives
'("melpa" . "https://snapshots.melpa.org/packages/") t)
Or to switch from MELPA stable to the new releases channel, replace
(add-to-list 'package-archives
'("melpa" . "https://stable.melpa.org/packages/") t)
with
(add-to-list 'package-archives
'("melpa" . "https://releases.melpa.org/packages/") t)
Note that in these examples the name “melpa” is used, regardless of what channel is used. Since this is just a local name, and you should never enable more than one MELPA channel anyway, this is a reasonable name. If you want to use a more precise name, like “melpa-snapshots”, that makes sense too.
At lease when switching from the old “regular” MELPA channel to the
new snapshots channel, you have to first remove all installed
packages and then reinstall them. Remember, we are switching from
timestamps such as 20260701.1234 to “smaller” version strings such
as 1.2.3.0.20260701.4. Because the former is greater (according to
version<), package.el won’t automatically update to the latter.
Considering the version strings at face value, doing so would be a
downgrade.
So start by modifying package-archives (as shown above) and copying
~/.config/emacs/elpa/ to some other location, before exiting Emacs.
Then restart Emacs and run M-x package-refresh-contents, followed by
M-x package-install-selected-packages
Nowadays, when you explicitly install a package, package-install
records that fact in the variable package-selected-packages, and if
some packages are listed in that variable without actually being
installed, then M-x package-install-selected-packages offers to to
reinstall them.
However, that was not always the case, or maybe some packages are
missing from that variable for some other reason. To really make sure
that all packages will be reinstalled, you should compare the contents
of the new ~/.config/emacs/elpa/ with that of the directory you
previously moved out of the way. If any packages are missing, then
the most likely cause is, that some other packages, which you have
explicitly installed, used to depend on them, but no longer do. If,
on the other hand, you notice, that some package which you still want
are missing, then just reinstall them explicitly.
Personally, I recommend you soon switch from the “legacy” channel, which you are currently using, to the respective “experimental” channel. If you want to play it safe, maybe wait a few weeks, in case something unexpectedly explodes.
The more interesting question is whether to use snapshots/unstable or releases/stable, i.e., which type of channel you should use, as opposed to which “generation” of a given type you should use. You have already made that decision, so the short answer is “stick to your decision”.
However, the new generation moves the needle somewhat, so you might wonder whether the time has come to switch from using snapshots to using just releases. (The main reason being that for packages that have not been released even once, the releases channel now features the same snapshots as the snapshots channel, instead of dropping those packages entirely.)
IMO that unfortunately isn't enough just yet. The new channels may, over time, encourage maintainers to release more often, resp. start releasing in the first place. I very much hope that will happen, and once it does, I will happily recommend installing releases. But for now the rational for why snapshots should be preferred remains unchanged:
By using the releases channel you can avoid regressions in actively maintained packages, but at the same time you opt-in to using severely outdated releases of other packages. A regression is unfortunate, but since those happen in packages being actively worked on, the fix will likely follow suit soon. The same cannot be said if a critical bug was fixed three years ago and no release has been created since then. While not impossible, it is unlikely that the maintainer of such a package will decide next week, that the time for a new release has finally come.
Package-Build is the tool used to build the package tarballs distributed on MELPA. Alongside the creation of the new MELPA channels, I have also created a new release of this package.
This has been in the making for a few years, so v5.0.0 is a big release consisting of 270 commits. The release notes can be found here. If you are a downstream of this package, then please have a look soon, and make the necessary adjustments. This release comes with breaking changes, but where possible I have kept many obsolete functions and variables. For now at least. I plan to remove these fairly soon, because (potentially accidentally) using them, means missing out on many of the improvements in this release.
While it was always possible to take MELPA, make some adjustments, and then publish your own ELPA, that was rather unwieldy. The MELPA repository contains many files (and I don’t mean the recipes), which look relevant enough for you to want to study them first, and their number made that a daunting task.
I have now created the MyELPA project, which is much simpler and allows anyone to easily publish their own ELPA. Like MELPA it uses Package-Build, but is much less complex. While it removes many bits that are unnecessary when just publishing a small ELPA, it also adds Forgejo (used on Codeberg) and Github action workflows, which greatly simplifies publishing your ELPA. By default your ELPA is published using Forgejo or Github pages and the published webpage is rather blant, but you are free to change the hosting, domain and/or the amount of fluff you add to your landing page.
To learn how to create your own ELPA, visit the MyELPA wiki.
Not every package has to be added to MELPA. Sometimes I get the impression that some authors add their packages to MELPA, even if they realize that they probably won't be used by anyone but themselves, just because it is more convenient for them to be able to easily install their own packages the same way as any other package.
For example, I think that very incomplete color themes and packages that have been vibe-coded in a single day, are best left out of MELPA.
I hope that by making it easier to publish one's own ELPA, Chris' workload can be reduced. For years now, and week after week, he reviews all recipe submissions MELPA receives, almost entirely by himself.
I make a living working on Magit, Transient and many other packages, and on MELPA and the Emacsmirror, and then some. Donations by users of these packages and projects are my only income, so if you benefit from my work and can afford it, please consider making a contribution. — Thanks!
Comments on Reddit.