quelpa: install Emacs packages straight from a source checkout
Build and install your Emacs Lisp packages on-the-fly directly from source
At a glance
- What is it?
- quelpa fetches an Emacs Lisp package from a version control system, builds an ELPA compatible archive from it, and installs it through package.el, so packages that are not on MELPA can be managed like any other. The trade-off is that every install pulls a toolchain and a source tree into your Emacs configuration.
- Who is it for?
- Adopt quelpa if you need a package that MELPA does not carry, or you want to test a development version of one you already use, and you are comfortable letting a build happen inside your Emacs session. Skip it if every package you need is on MELPA or Nonfree, since package.el already covers that case with far less machinery.
- Can I use it commercially?
- Yes, with conditions. GPL-3.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
- Is it still maintained?
- Yes. The repository last received commits 115 days ago.
- What is it written in?
- Mainly Emacs Lisp, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 24, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A package manager for things MELPA does not carry
MELPA builds ELPA archives from source and publishes them to an archive. quelpa takes a different route: it fetches a package's source code, builds an ELPA compatible package on your machine and installs that locally with package.el. The result behaves like any other package afterwards, so M-x list-packages still shows it and still lets you remove it.
The problem it solves is narrow and real. A package that is not on MELPA, or a development version of a package you already depend on, is otherwise awkward to install without hand rolling a build in your init file. quelpa turns that into one call.
The README is explicit about the range of uses: managing personal packages, testing development versions of other packages, and as a helper while developing a package yourself, where you want to test building, compiling and installing it. The last of these is the one that gets least attention in blog posts about the tool and is arguably the most useful for Emacs contributors.
The licence is GPL-3.0, which is the normal choice for an Emacs package and is worth noting only because it affects how you redistribute a modified version.
Recipes reuse MELPA's format verbatim
The recipe format is MELPA's, not a new one, which removes a layer of learning. A recipe is a list with a package name and a fetcher:
(quelpa '(hydra :repo "abo-abo/hydra" :fetcher github))Given that, quelpa retrieves the source, builds the package and installs it. The fetcher names cover a wide range of version control systems: git, github, bzr, hg, svn, cvs, darcs, fossil and wiki for EmacsWiki.
Two changes in the project's history show how the tool has been maintained. The news section records support for the elpa-devel version scheme, for example versions written as 0.27.0.20220914.164819, using the :version-type elpa option in recipes. It also records a switch from shallow clone to partial clone for git recipes in 2021, which changes how much history is fetched and therefore how large the download is for a repository with a long history.
Because the recipe format is shared with MELPA, a recipe written for one works in the other, and the documentation points at the MELPA recipe format page for the details.
Three ways to get quelpa itself installed
The first route is the ordinary package route. With MELPA configured, run M-x package-install, type quelpa and press RET.
The second is to place the file quelpa.el into a directory on your Emacs load-path and then require it in your init file with (require 'quelpa). That works without any package archive, and it suits a setup that avoids MELPA entirely or that pins a specific copy of the source.
The third is a bootstrap snippet that fetches and evaluates the file directly from the repository, and it handles the upgrade of itself:
(unless (package-installed-p 'quelpa)
(with-temp-buffer
(url-insert-file-contents "https://raw.githubusercontent.com/quelpa/quelpa/master/quelpa.el")
(eval-buffer)
(quelpa-self-upgrade)))The snippet only acts when quelpa is not already installed as a package, then downloads the master branch of the single file, evaluates it and calls the self upgrade command. Fetching one file over HTTPS is a small footprint, but evaluating downloaded code at startup is a decision worth making consciously on a shared machine.
The documentation notes that you should use only one installation method per setup, since mixing a load-path copy with a package-installed copy gives you two candidates for which version of the file runs.
Install by package name or by an explicit recipe
There are two entry points and they differ in what you need to know.
By package name, you can interactively run M-x quelpa RET and type a name with completion, or call the function from Lisp code with (quelpa 'package-name). The package is then fetched from its repository, built and installed.
By recipe, you supply the source location yourself. This is the path for a package that is not on MELPA, and the README gives this shape:
(quelpa '(discover-my-major :fetcher git :url "https://framagit.org/steckerhalter/discover-my-major.git"))The difference matters for how the tool behaves afterwards. Once a package has been installed with its own recipe, quelpa remembers it, and the next M-x quelpa RET offers to upgrade or install that package again. A package installed by name alone does not carry a recipe with it, so the memory of where it came from lives in quelpa's cache rather than in your init file.
A practical consequence: if you install by recipe once interactively and do not record that recipe in your configuration, the next fresh machine has no way to reproduce it.
Upgrades are off by default, and the cache drives the bulk path
By default quelpa does not upgrade installed packages. You can change that globally with M-x customize-variable, setting quelpa-upgrade-p, or override it per call.
For a single package there are three ways to ask for an upgrade: call quelpa with a universal prefix argument, which is C-u M-x quelpa RET; pass the :upgrade keyword, as in (quelpa 'package-name :upgrade t); or run M-x quelpa-upgrade RET, which lists all packages installed by quelpa. When evaluating a buffer of calls, a package can be held back with :upgrade nil, written as (quelpa 'package-name :upgrade nil).
The bulk path is M-x quelpa-upgrade-all, which relies on the cache file named by the variable quelpa-cache-file. That cache is updated after every quelpa invocation, so it is a record of what quelpa believes it installed rather than a query of package.el. By default this command also upgrades quelpa itself, which you disable by setting quelpa-self-upgrade-p to nil.
Upgrading everything at startup is possible but the documentation warns it can slow Emacs's startup considerably. The alternative is to run it at most every seven days once the init files have loaded:
(setq quelpa-upgrade-interval 7)
(add-hook #'after-init-hook #'quelpa-upgrade-all-maybe)That hook runs after startup rather than during it, which keeps the startup cost separate from the network work.
package.el manages the result, and the cache can drift
Because installation goes through Emacs's built-in package library, the installed packages remain visible in M-x list-packages and removable from there. That is the main reason to prefer this route over hand installing a package file.
The documented wrinkle is that deleting a package that way does not yet affect quelpa's cache, so quelpa still considers the package to have been installed with quelpa. In other words, the two views of what is installed can disagree, and the cache is the one that is stale. The documentation describes the default behaviour of each command regarding obsoleted versions:
- M-x quelpa-upgrade-all, M-x quelpa-upgrade and C-u M-x quelpa remove obsoleted packages by default - M-x quelpa does not remove an obsoleted package by default
Old versions are otherwise cleaned up automatically after an upgrade, and you can turn that off globally with quelpa-autoremove-p set to nil, or per call with the :autoremove nil option, as in (quelpa 'foo :autoremove nil). Keeping an old version around is occasionally useful when a new release breaks your setup and you have not yet fixed it.
The net effect is that two independent views of your package state exist, and neither is automatically reconciled with the other.
Toolchain requirements, and a repository built for Emacs developers
The requirements are modest on the surface: Emacs 25.1, tar, and git, with version 2.20 or later recommended. The catch is the sentence that follows: every build requires the corresponding build tool, so installing a subversion hosted package means subversion has to be installed as well. The documentation also warns that a package fetched with one version control system can have dependencies that require a different one, so installing the most common tools up front avoids a confusing mid-build failure.
The repository layout shows a package maintained by people who work on Emacs packaging. There is an Eask file, a Makefile together with makem.sh for building and testing, a Vagrantfile, a bootstrap.el, a test/ directory and a world-domination.org file, plus the single Quelpa source file quelpa.el at the root.
That Makefile is not project specific. It is the makem.sh script by alphapapa, version 0.5, whose rules forward to makem.sh with options for dependencies, linters, a sandbox mode and debug and verbosity flags.
Maintenance is uneven on paper. The last push was on 2026-07-01, while the only release tag is v1.0 from 2020-08-21. The package is distributed through MELPA and stable.melpa.org as well as the repository, so you can take the published archive rather than tracking a commit.
Editorial conclusion
Adopt quelpa if you need a package that MELPA does not carry, or you want to test a development version of one you already use, and you are comfortable letting a build happen inside your Emacs session. Skip it if every package you need is on MELPA or Nonfree, since package.el already covers that case with far less machinery. Before you wire it into your init file, check that the version control tools for your chosen fetcher are on PATH, because a missing tool fails at build time rather than at install time, and read the cache behaviour in the documentation, since deleting a package through package.el leaves quelpa's cache out of step. The last push was on 2026-07-01 and the only release tag is v1.0 from 2020-08-21.
Frequently asked questions
What is the difference between quelpa and MELPA?
MELPA builds packages from source and publishes ELPA archives to an archive. quelpa does the same build locally on your machine from a recipe you give it, then installs the result with package.el, which is how you can install a package that is not on MELPA.
How do I upgrade packages installed with quelpa?
Upgrades are off by default. You can enable them globally with the variable quelpa-upgrade-p, ask for one package with C-u M-x quelpa RET or the :upgrade keyword, or list everything quelpa installed with M-x quelpa-upgrade RET.
Does deleting a quelpa package from package.el remove it for quelpa?
Not immediately. The documentation states that deleting a package this way does not yet affect the quelpa cache, so quelpa still considers it to have been installed with quelpa. The two views of your installed packages can therefore disagree.
Which version control systems can quelpa fetch from?
The fetcher list covers git, github, bzr, hg, svn, cvs, darcs, fossil and wiki for EmacsWiki. You need the matching tool installed on your system, since each build requires its own build tool.
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/quelpa-quelpa)Was this useful?