Skip to content
Switch branches/tags


Cask can be likened to venv or maven for Emacs Lisp development, although, as with all things emacs, is decidedly less sophisticated (but no less arcane).

Cask provisions dependencies within a sandbox via a user-defined “Cask” file analogous to requirements-dev.txt or pom.xml.

Cask does not absolve you of having to learn emacs’s command flags. Cask only constructs the sandbox, one for each version of emacs you choose to test.


git clone
make -C cask install

Not-so-quick start

With just this baseline “Cask” file, you can run most of the commands described in

(source gnu)
(source melpa)

(package-file "your-main-file.el")

To run ert tests under an older emacs:

EMACS=emacs-25.3 cask emacs --batch -l mytest.el -f ert-run-tests-batch

We have deprecated the cask exec invocation, and consequently no longer recommend cask exec ert-runner nor cask exec ecukes .

Typical Makefile Usage

Egregious boilerplate follows:

export EMACS ?= $(shell which emacs)
CASK_DIR := $(shell cask package-directory)

$(CASK_DIR): Cask
	cask install
	@touch $(CASK_DIR)

.PHONY: cask
cask: $(CASK_DIR)

.PHONY: compile
compile: cask
	! (cask eval "(let ((byte-compile-error-on-warn t)) \
	                 (cask-cli/build))" 2>&1 \
	   | egrep -a "(Warning|Error):") ; \
	  (ret=$$? ; cask clean-elc && exit $$ret)

.PHONY: test
test: compile
	cask emacs --batch -L ./test -l readme-test -f ert-run-tests-batch

Typical CI Usage

Cask, in conjunction with setup-emacs, is commonly used in Github Actions. Egregious boilerplate follows:

    runs-on: ubuntu-latest
          - 26.3
          - 27.2
          - 28.1
      - uses: actions/checkout@v2
      - uses: purcell/setup-emacs@master
          version: ${{ matrix.emacs-version }}
      - uses: actions/cache@v2
        id: cache-cask-packages
          path: .cask
          key: cache-cask-packages-000
      - uses: actions/cache@v2
        id: cache-cask-executable
          path: ~/.cask
          key: cache-cask-executable-000
      - uses: cask/setup-cask@master
        if: steps.cache-cask-executable.outputs.cache-hit != 'true'
          version: snapshot
      - run: echo "$HOME/.cask/bin" >> $GITHUB_PATH

Frequently Asked Questions

Why does install “not know where to install”?
After assaying cross-platform schemes like systemd-path and XDG_DATA_HOME to figure out a suitable install directory, Cask resorts to the old, unspoken standbys of ~/.local/bin and ~/bin. If neither of those are present, then make install gives up with that error. I couldn’t determine a more standard method last I asked
Why is everything you say inconsistent with
I would disregard nearly everything at, especially the Quickstart page. In particular, I would not require cask in your dot.emacs since cask is now largely a command-line tool independent of whatever you do within emacs. If you are calling cask-initialize in your dot.emacs or harken back to the bygone era of pallet, I’m afraid you’re on your own.
Why must I replicate dependencies in the Cask file?
You mustn’t, but probably more than half of Cask deployments in the wild needlessly do. cask list automatically shows your package’s dependencies if you specify them pro forma in a Package-Requires header. The oft-confused development stanza is analogous to requirements-dev.txt. Only packages required by your testing apparatus, e.g., ert-runner, should be added there.
Doesn’t Cask make things more complicated?
Yes, because it forces you to test your package under multiple versions of emacs. Most packages don’t do any testing at all, which is why emacs has lost credibility with the computing public.
Is Cask a vassal of MELPA?
Yes, Cask’s early development history is intertwined with that of MELPA’s package-build. Cask employs that module for all packaging tasks including dependency provisioning.