Chapter 5: Package Management
Standing on the Shoulders of Giants
Remember when I said Emacs can do everything? I wasn’t exaggerating. There’s a package for everything. Want to control Spotify from Emacs? There’s a package. Want to play Dungeons & Dragons? Package. Want to turn Emacs into a full-featured IDE that makes VS Code jealous? Oh boy, are there packages.
The Emacs package ecosystem is like a candy store where everything is free and the candy makes you more productive. Let’s go shopping.
The Package System: ELPA, MELPA, and Beyond
Emacs has several package repositories:
- GNU ELPA: The official repository, conservative and stable
- MELPA: The community repository, bleeding edge
- MELPA Stable: MELPA but with version tags
- NonGNU ELPA: For packages that don’t assign copyright to FSF
Add them to your config:
;; Initialize package system
(require 'package)
;; Add package archives
(setq package-archives '(("gnu" . "https://elpa.gnu.org/packages/")
("melpa" . "https://melpa.org/packages/")
("nongnu" . "https://elpa.nongnu.org/nongnu/")))
;; Initialize packages
(package-initialize)
;; Fetch package list if needed
(unless package-archive-contents
(package-refresh-contents))
🚸 IDE Refugee Note: This is like npm, pip, or cargo, but for your editor. And unlike VS Code extensions, these packages can fundamentally change how Emacs works, not just add features.
Your First Package Installation
Let’s install which-key, a package that shows available keybindings:
M-x package-install RET which-key RET
Now configure it:
(require 'which-key)
(which-key-mode 1)
(setq which-key-idle-delay 0.3) ; Show hints after 0.3 seconds
Now when you type a prefix key like C-x and wait, you’ll see all available completions. It’s like training wheels for keybindings!
Use-Package: The Game Changer
Managing packages manually gets tedious. Enter use-package, the declarative package configuration tool:
;; Install use-package if not already installed
(unless (package-installed-p 'use-package)
(package-refresh-contents)
(package-install 'use-package))
(require 'use-package)
(setq use-package-always-ensure t) ; Auto-install packages
Now you can declare packages beautifully:
(use-package magit
:ensure t
:bind ("C-x g" . magit-status)
:config
(setq magit-display-buffer-function #'magit-display-buffer-same-window-except-diff-v1))
(use-package company
:ensure t
:hook (prog-mode . company-mode)
:config
(setq company-idle-delay 0.1
company-minimum-prefix-length 2))
🤔 Why Though? Use-package makes your config self-documenting, auto-installs missing packages, and lazy-loads them for faster startup. It’s the difference between a config file and a config masterpiece.
Essential Packages Everyone Should Have
1. Completion and Navigation
;; Vertico: Better minibuffer completion
(use-package vertico
:ensure t
:init
(vertico-mode))
;; Orderless: Fuzzy matching
(use-package orderless
:ensure t
:custom
(completion-styles '(orderless basic))
(completion-category-overrides '((file (styles basic partial-completion)))))
;; Consult: Search and navigation commands
(use-package consult
:ensure t
:bind (("C-s" . consult-line)
("C-x b" . consult-buffer)
("M-y" . consult-yank-pop)))
;; Marginalia: Annotations in minibuffer
(use-package marginalia
:ensure t
:init
(marginalia-mode))
2. Project Management
;; Projectile: Project navigation
(use-package projectile
:ensure t
:init
(projectile-mode +1)
:bind-keymap
("C-c p" . projectile-command-map))
;; Treemacs: File tree sidebar
(use-package treemacs
:ensure t
:bind
(:map global-map
("M-0" . treemacs-select-window)
("C-x t t" . treemacs)))
3. Git Integration
;; Magit: The best git interface ever created
(use-package magit
:ensure t
:bind ("C-x g" . magit-status))
;; Git-gutter: Show changes in fringe
(use-package git-gutter
:ensure t
:hook (prog-mode . git-gutter-mode)
:config
(setq git-gutter:update-interval 0.02))
4. Better Editing
;; Multiple cursors
(use-package multiple-cursors
:ensure t
:bind (("C-S-c C-S-c" . mc/edit-lines)
("C->" . mc/mark-next-like-this)
("C-<" . mc/mark-previous-like-this)))
;; Expand region: Semantic selection
(use-package expand-region
:ensure t
:bind ("C-=" . er/expand-region))
;; Rainbow delimiters: Colored parentheses
(use-package rainbow-delimiters
:ensure t
:hook (prog-mode . rainbow-delimiters-mode))
Language-Specific Packages
Python Development
(use-package python-mode
:ensure t
:mode "\\.py\\'"
:config
(setq python-indent-offset 4))
(use-package elpy
:ensure t
:init
(elpy-enable))
(use-package blacken ; Auto-format with black
:ensure t
:hook (python-mode . blacken-mode))
JavaScript/TypeScript
(use-package js2-mode
:ensure t
:mode "\\.js\\'"
:config
(setq js2-basic-offset 2))
(use-package typescript-mode
:ensure t
:mode "\\.ts\\'")
(use-package prettier-js
:ensure t
:hook ((js2-mode . prettier-js-mode)
(typescript-mode . prettier-js-mode)))
Web Development
(use-package web-mode
:ensure t
:mode (("\\.html?\\'" . web-mode)
("\\.css\\'" . web-mode)
("\\.jsx\\'" . web-mode))
:config
(setq web-mode-markup-indent-offset 2
web-mode-css-indent-offset 2
web-mode-code-indent-offset 2))
(use-package emmet-mode
:ensure t
:hook (web-mode css-mode))
The Power Packages That Change Everything
LSP Mode: IDE Features
(use-package lsp-mode
:ensure t
:commands (lsp lsp-deferred)
:hook ((python-mode . lsp-deferred)
(js2-mode . lsp-deferred)
(typescript-mode . lsp-deferred))
:config
(setq lsp-idle-delay 0.6
lsp-prefer-capf t))
(use-package lsp-ui
:ensure t
:hook (lsp-mode . lsp-ui-mode)
:config
(setq lsp-ui-doc-enable t
lsp-ui-doc-delay 0.5))
Company: Autocompletion
(use-package company
:ensure t
:hook (after-init . global-company-mode)
:config
(setq company-idle-delay 0.1
company-minimum-prefix-length 2
company-show-numbers t))
(use-package company-box ; Better UI
:ensure t
:hook (company-mode . company-box-mode))
Flycheck: Syntax Checking
(use-package flycheck
:ensure t
:init (global-flycheck-mode)
:config
(setq flycheck-display-errors-delay 0.3))
Theme Packages: Make It Beautiful
;; Doom themes: Beautiful modern themes
(use-package doom-themes
:ensure t
:config
(load-theme 'doom-dracula t)
(doom-themes-visual-bell-config)
(doom-themes-org-config))
;; Doom modeline: Pretty status bar
(use-package doom-modeline
:ensure t
:init (doom-modeline-mode 1)
:config
(setq doom-modeline-height 25
doom-modeline-icon t))
;; All-the-icons: File icons
(use-package all-the-icons
:ensure t
:if (display-graphic-p))
;; Run M-x all-the-icons-install-fonts on first install
Life-Changing Utility Packages
;; Undo-tree: Visualize undo history
(use-package undo-tree
:ensure t
:init (global-undo-tree-mode)
:config
(setq undo-tree-visualizer-timestamps t
undo-tree-visualizer-diff t))
;; Avy: Jump to any character
(use-package avy
:ensure t
:bind ("C-;" . avy-goto-char-timer))
;; Helpful: Better help buffers
(use-package helpful
:ensure t
:bind (("C-h f" . helpful-callable)
("C-h v" . helpful-variable)
("C-h k" . helpful-key)))
;; Which-key: Discover keybindings
(use-package which-key
:ensure t
:init (which-key-mode)
:config
(setq which-key-idle-delay 0.3))
Managing Package Updates
;; Auto-update packages
(use-package auto-package-update
:ensure t
:config
(setq auto-package-update-delete-old-versions t
auto-package-update-hide-results t)
(auto-package-update-maybe))
;; Or manually:
;; M-x package-list-packages
;; Then press 'U' to mark updates, 'x' to install
Creating Your Own Package
Yes, you can create packages too!
;;; my-amazing-package.el --- Does amazing things -*- lexical-binding: t -*-
;; Author: Your Name
;; Version: 1.0
;; Package-Requires: ((emacs "27.1"))
;;; Commentary:
;; This package does amazing things
;;; Code:
(defun my-amazing-function ()
"Do something amazing."
(interactive)
(message "Amazing!"))
(provide 'my-amazing-package)
;;; my-amazing-package.el ends here
Package Debugging
When packages misbehave:
;; Debug package loading
(setq use-package-verbose t)
;; Profile package loading
(use-package benchmark-init
:ensure t
:config
(add-hook 'after-init-hook 'benchmark-init/deactivate))
;; Then M-x benchmark-init/show-durations-tree
;; Isolate package issues
;; Start Emacs with: emacs -Q
;; Then load only the problematic package
The Package Ecosystem Tour
Some packages that showcase Emacs’s versatility:
- org-roam: Zettelkasten note-taking
- elfeed: RSS reader
- mu4e: Email client
- erc: IRC client
- pdf-tools: Better PDF viewing
- vterm: Proper terminal emulator
- dired-sidebar: File manager sidebar
- dashboard: Startup dashboard
- perspective: Workspace management
- hydra: Create custom command menus
🎯 Pro Tip: Don’t install everything at once! Add packages as you need them. Your config should grow organically with your needs.
Package Recipes: Complete Configurations
The Writer’s Setup
(use-package olivetti ; Distraction-free writing
:ensure t
:hook (text-mode . olivetti-mode)
:config
(setq olivetti-body-width 80))
(use-package writeroom-mode ; Full-screen writing
:ensure t
:bind ("C-c w" . writeroom-mode))
(use-package writegood-mode ; Writing style hints
:ensure t
:hook (text-mode . writegood-mode))
The Developer’s Setup
(use-package format-all ; Auto-format any language
:ensure t
:hook (prog-mode . format-all-mode))
(use-package editorconfig ; Respect .editorconfig
:ensure t
:config
(editorconfig-mode 1))
(use-package docker
:ensure t
:bind ("C-c d" . docker))
🎮 Package Exercises
- The Explorer: Install and configure 5 packages you’ve never used
- The Curator: Create a themed package collection (all productivity, all git, etc.)
- The Speed Demon: Profile your packages and optimize load time
- The Creator: Write a simple package that solves a personal problem
- The Minimalist: Find the minimum set of packages you actually need
What’s Next?
Chapter 6 introduces Org-mode, which isn’t just a package—it’s a way of life. It’s the reason many people switch to Emacs and never leave. You’re about to understand why.
But remember: packages are tools, not goals. The perfect Emacs setup is the one that helps you work better, not the one with the most packages. Though having a lot of packages is pretty fun too.
“I came for the text editor, I stayed for the packages, I became one with the ecosystem.” —The Emacs Package Enlightenment Process
Chapter 5 Summary
- MELPA is your candy store
- use-package is your shopping cart
- Essential packages for everyone: completion, git, projects
- Language packages for specific needs
- Don’t install everything—grow organically
- Your package collection is as unique as your workflow
- The ecosystem is vast—explore it!