(This is a manual paraphrase from my Japanese article.)
This article briefly explains how to manage (download and install) Emacs packages via the quickstart feature of package.el.
With this approach, you don't have to use package-* in your initialization file (e.g. ~/.emacs.d/init.el), let alone use-package, etc.
For detailed information, please refer to the comment of "Quickstart" in package.el or the Info node "(emacs) Package Installation".
Pros and Cons
Pros: Startup may be faster since autoloads are calculated in advance
Cons: You have to restart Emacs everytime you add packages to install
Example Setup
Disable package.el at startup in your early-init.el:
(setq package-enable-at-startup nil)
Create the installer script file (e.g. /path/to/installer.el):
;;; installer.el --- Generate package autoloads -*- lexical-binding: t; -*-
;;; Commentary:
;; [...]
;;; Code:
;; `package-vc-install' doesn't have `DONT-SELECT' argument like in
;; `package-install'.
(setq custom-file (make-temp-file "installer"))
(require 'package)
(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t)
(package-initialize)
(unless package-archive-contents
(package-refresh-contents))
(dolist (pkg '(ddskk
flymake-perlcritic
auth-source-xoauth2-plugin
;; [...]
))
(unless (package-installed-p pkg)
(package-install pkg 'dont-update-package-selected-packages)))
(package-vc-install "https://codeberg.org/gemmaro/cwmrc-mode")
(package-quickstart-refresh)
;; This is not a package.
;;; installer.el ends here.
Then run the script:
emacs --batch --load /path/to/installer.el
Now the packages are downloaded under the ~/.emacs.d/elpa/ and the ~/.emacs.d/package-quickstart.el is generated.
Finally, load the generated file in your init file:
(load-file package-quickstart-file)
Dynamic Module Package
Some packages have dynamic modules, which require C compilation.
Here is an example to install flymake-sqlite on OpenBSD, which is a Flymake backend which utilizes the SQLite C interface.
(condition-case err
(package-vc-install "https://codeberg.org/gemmaro/flymake-sqlite")
('error (message "[error:flymake-sqlite] maybe cancelled?")))
(with-environment-variables
(("C_INCLUDE_PATH" (concat "/usr/local/include:" (getenv "C_INCLUDE_PATH")))
("LIBRARY_PATH" (concat "/usr/local/lib:" (getenv "LIBRARY_PATH"))))
(let* ((dir (concat user-emacs-directory "elpa/flymake-sqlite"))
(ls (process-lines "gmake"
"--directory" dir)))
(message "[info:out] %S" ls)))
License
Copyright (C) 2026 gemmaro
Copying and distribution of this file, with or without modification,
are permitted in any medium without royalty provided the copyright
notice and this notice are preserved. This file is offered as-is,
without any warranty.
Top comments (0)