Setting up a Common Lisp environment
Setting up a Common Lisp environment is not easy for beginners. In this note1, we will take a logical and progressive approach:
- SBCL -> Common Lisp implementation.
- Emacs + Sly -> Common Lisp IDE.
- ASDF -> build system.
- Quicklisp -> package manager.
- Quickproject -> easy creation of Common Lisp projects as ASDF systems.
- Buildapp -> easy compilation for your Lisp projects.
- StumpWM -> full-blown Common Lisp window manager that will lispify your desktop experience.
You can already stop after step 2 and be productive in Lisp, or study the many great Lisp books out there.
SBCL
I use SBCL as my Common Lisp implementation of choice. Source code and binaries can be found here.
I usually prefer to install the latest version instead of relying on my distro's current version (although I use Debian Sid). Relevant quote from StumpWM's GitHub page (a Common Lisp window manager that we will install below):
Please do not install SBCL using your distributions package manager, especially Ubuntu. If you do so it is likely that you'll run into problems when building StumpWM due to using obsolete versions of the dependencies.
As of , we will download SBCL v2.6.2. I prefer to
install SBCL in ~/bin and to create a symlink (~/bin is in my
PATH). From the directory in which you downloaded the tarball:
tar xavf sbcl-2.6.2-x86-64-linux-binary.tar.bz2 cd sbcl-2.6.2-x86-64-linux mkdir ~/bin/sbcl-2.6.2 INSTALL_ROOT=/home/alc/bin/sbcl-2.6.2 sh install.sh ln -s ~/bin/sbcl-2.6.2/bin/sbcl ~/bin/sbcl
Adapt this to your own needs, of course. Test the install:
sbcl --version
SBCL 2.6.2
Sly
With just SBCL and Emacs as an IDE, you can already start hacking in Common Lisp.
I personally use Sly, but SLIME is another option. Here's how I
install it in Emacs with use-package – you will find this code in
my Emacs configuration here:
(use-package sly
;; Sylvester the Cat's Common Lisp IDE.
;; https://github.com/joaotavora/sly
:ensure t
:config
(setq inferior-lisp-program "sbcl"
org-babel-lisp-eval-fn #'sly-eval))
You can also using the package manager directly:
M-x package-install RET sly RET
However, don't forget to set your default Lisp by evaluating this expression:
(setq inferior-lisp-program "sbcl")
Launch it with M-x sly and start exploring! Sly will run SBCL for
you and connect to the Lisp image. To quit, you can type , and
choose the sayoonara command.
ASDF
Another System Definition Facility. ASDF is bundled with SBCL.
In this section we will simply register our ASDF systems. You can use
any directory you want for this; I'll use ~/src/ below. These
instructions are documented here, as of .
Create the configuration directory for ASDF.
mkdir ~/.config/common-lisp/source-registry.conf.d/
Create a
.conffile – I usemy-asdf.conf. In this file, add a line like this one:(:tree "/home/alc/src/")
You should find this file in my dotfiles.
This will tell ASDF to recursively scan this directory looking for
.asdfiles. Of course choose your own dir 🙂We will test things by creating a typical ASDF system in the directory you used above:
mkdir my-asdf-test
Then create these 2 files:
;; my-asdf-test.asd (system definition) (asdf:defsystem #:my-asdf-test :serial t :components ((:file "my-asdf-test"))) ;; my-asdf-test.lisp (package + a small function) (defpackage #:my-asdf-test (:use #:cl)) (in-package :my-asdf-test) (defun main () (write-line "Hello, world"))
Here's a Sly session that shows that ASDF can detect the system:
CL-USER> (asdf:load-system :my-asdf-test) ; compiling file "/home/alc/src/my-asdf-test/my-asdf-test.lisp" (written 08 MAR 2026 05:20:57 PM): ; wrote /home/alc/.cache/common-lisp/sbcl-2.6.2-linux-x64/home/alc/src/my-asdf-test/my-asdf-test-tmpGHU3ALSV.fasl ; compilation finished in 0:00:00.008 T CL-USER> (in-package :my-asdf-test) #<PACKAGE "MY-ASDF-TEST"> MY-ASDF-TEST> (main) Hello, world "Hello, world"
Quicklisp
Quicklisp is a library manager for Common Lisp. If you need a dependency for your project, it's a good place to start.
Slow version
Download the install script.
wget https://beta.quicklisp.org/quicklisp.lisp
Run SBCL and load the Lisp file.
sbcl --load quicklisp.lisp
Install Quicklisp. I prefer to install it in
~/.quicklisp, install it wherever you want.(quicklisp-quickstart:install :path ".quicklisp/")
Notify SBCL about Quicklisp. Add this to your
.sbclrcfile:#-quicklisp (let ((quicklisp-init (merge-pathnames ".quicklisp/setup.lisp" (user-homedir-pathname)))) (when (probe-file quicklisp-init) (load quicklisp-init)))
Fast version
curl -o /tmp/ql.lisp http://beta.quicklisp.org/quicklisp.lisp
sbcl --no-sysinit --no-userinit --load /tmp/ql.lisp \
--eval '(quicklisp-quickstart:install :path "~/.quicklisp")' \
--eval '(ql:add-to-init-file)' \
--quit
Optional
Run Sly in Emacs and download a package. Here's a Sly session you can reproduce:
;
; ( \
; \ \
; / / |\\
; / / .-`````-. / ^`-.
; \ \ / \_/ {|} `o
; \ \ / .---. \\ _ ,--'
; \ \/ / \, \( `^^^ Take this REPL, brother, and may it serve you well.
; \ \/\ (\ )
; \ ) \ ) \ \
; ) /__ \__ ) (\ \___
; (___)))__))(__))(__)))
;
; Dedicated output stream setup (port 45563)
; Redirecting all output to this MREPL
; SLY NIL (#<MREPL mrepl-1-1>)
CL-USER> (ql:quickload "alexandria")
To load "alexandria":
Load 1 ASDF system:
asdf
Install 1 Quicklisp release:
alexandria
; Fetching #<URL "http://beta.quicklisp.org/archive/alexandria/2024-10-12/alexandria-20241012-git.tgz">
; 55.94KB
==================================================
57,281 bytes in 0.02 seconds (2796.92KB/sec)
; Loading "alexandria"
[package alexandria]..............................
[package alexandria-2]
("alexandria")
CL-USER> (alexandria:clamp 150 0 100)
100 (7 bits, #x64, #o144, #b1100100)
(clamp clamps a number value into [min, max] range. See Alexandria's
documentation.)
Since Quicklisp and ASDF work together, you can also load your own
ASDF systems with ql:quickload instead of what we did above with
asdf:load-system. Note that you can put your ASDF systems in
~/.quicklisp/local-projects.
Quickproject
Quickproject is pretty neat for creating a Common Lisp project from scratch. We will use it to create another small test project, but faster this time. The project we create here will also be compiled in the next section.
Using Sly, create a project in the source directory you selected earlier:
(ql:quickload :quickproject) (quickproject:make-project #p"~/src/my-quickproject-test/")
In
my-quickproject-test.lisp, add thismainfunction after thein-packagedeclaration:(defun main (argv) (format t "Hello, ~A~%" (second argv)))
Load the project:
(ql:quickload :my-quickproject-test)
If it loads, perfect – go to the next section 🙂
Compilation
Buildapp is pretty cool.
Install it.
(ql:quickload :buildapp)
Build
buildappitself.(buildapp:build-buildapp)
Important: the binary will be created in the current directory, so move it somewhere useful (I'll use
~/binas it's in my PATH).We'll now build
my-quickproject-test!~/bin/buildapp --output my-quickproject-test \ --load-system my-quickproject-test \ --entry my-quickproject-test:mainRun the program with an argument:
❯ ./my-quickproject-test "World" Hello, World
StumpWM
StumpWM is a fantastic window manager written and configurable in Common Lisp. We will build it from source.
You can also check this page on ArchWiki.
Clone the StumpWM repository:
git clone https://github.com/stumpwm/stumpwm
Install the dependencies in SBCL/Sly:
(ql:quickload '("clx" "cl-ppcre" "alexandria"))Compile it:
./autogen.sh ./configure make
I prefer to link to the executable instead of using
make install:ln -s ~/src/stumpwm/stumpwm ~/bin/stumpwm
I start StumpWM with:
WM=stumpwm startx
Here's the corresponding
~/.xinitrcfile; adapt it to your own needs (I also use i3):#!/bin/sh WM="${WM:-i3}" case "$WM" in stumpwm) xrandr --dpi 96 export SBCL_HOME=/home/alc/bin/sbcl-2.6.2/lib/sbcl exec "$HOME/bin/stumpwm" ;; i3) xrandr --dpi 96 exec i3 ;; *) echo "Unknown WM: $WM" exit 1 ;; esacNotice the
SBCL_HOMEexport, it's important! The cause is here.- Run
WM=stumpwm startx: it should work.
Optional: Slynk
You can connect to the Lisp image used by StumpWM from Sly and interact with the window manager live using a Slynk server (no need to restart your window manager, you're in the Lisp world).
Check my config here, that's what I do.
Add this to your StumpWM
init.lisp:(in-package #:stumpwm) (ql:quickload '(:alexandria :slynk :local-time) :silent t) (defvar *slynk-server* nil) (defcommand slynk-start () () (unless *slynk-server* (setf *slynk-server* (slynk:create-server :port 4006 :dont-close t))) (message "Slynk server started.")) (defcommand slynk-stop () () (when *slynk-server* (slynk:stop-server *slynk-server*) (setf *slynk-server* nil) (message "Slynk server stopped.")))- From StumpWM, run the
slynk-startcommand. Then from Emacs, run
M-x sly-connectand connect tohttp://localhost:4006. You should be able to communicate with StumpWM! Try it:CL-USER> (stumpwm:message "hello")
The message should appear on the screen. How cool is that?
Optional: ttf-fonts
If you want to use the ttf-fonts module from StumpWM's contrib
repository, you will need clx-truetype, which is not in Quicklisp
anymore. Here's how to fix that:
Clone a version of it in
~/.quicklisp/local-projects.I used this one.
- Run
(ql:quickload "clx-truetype")once so dependencies are fetched (you can also include this line of code in your config). It should work. I personally use Jetbrains Mono:
(load-module "ttf-fonts") (xft:cache-fonts) (set-font (make-instance 'xft:font :family "JetBrains Mono" :subfamily "Regular" :size 12 :antialias t))
Footnotes:
This article was originally written around 2020 and was updated in 2026.

