Aside from managing an Emacs installation, Nix can also bundle Emacs packages.
For example, to produce a development shell that has Emacs available with Evil mode installed, use emacsWithPackages.
In this example flake, the build inputs include a version of Emacs based on emacs-nox with the Evil package added:
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
flake-utils.url = "github:numtide/flake-utils";
};
outputs = { nixpkgs, flake-utils, ... } :
flake-utils.lib.eachDefaultSystem (system:
let
pkgs = import nixpkgs { inherit system; };
in
{
devShells.default = pkgs.mkShell {
buildInputs = with pkgs; [
((emacsPackagesFor emacs-nox).emacsWithPackages(epkgs: [
epkgs.evil
]))
];
};
});
}
With the flake in place, a development shell is started by running nix develop, which opens a shell with Emacs installed and available.
To start Emacs directly, without having to start a sub shell first, use the --command flag:
nix develop --command emacs
Within this version of Emacs, the packages defined in the flake’s build inputs are available. This allows for reproducable setups of local development environments, or when using Emacs for batch processing, for example.
Nixpkgs automatically creates derivations based on the recipes available in Elpa, Elpa-devel, NonGNU Elpa and Melpa, which means most packages are available in Nix’s emacsPackage set1.
An Emacs package derivation
Emacs packages can be used even if they’re not available through Nixpkgs by writing a derivation.
For example, the ox-html-markdown-style-footnotes package is not available through any package manager, but it is useful for generating HTML from Org documents through batch processing. To bundle it with Emacs, write a derivation:
{ lib, fetchurl, trivialBuild }:
trivialBuild {
pname = "ox-html-markdown-style-footnotes";
version = "0.2.0";
src = fetchurl {
url = "https://raw.githubusercontent.com/jeffkreeftmeijer/ox-html-markdown-style-footnotes.el/0.2.0/ox-html-markdown-style-footnotes.el";
sha256 = "sha256-S+lzFpGY44OgXAeM9Qzdhvceh8DvvOFiw5tgXoXDrsQ=";
};
meta = with lib; {
description = "Markdown-style footnotes for ox-html.el";
homepage = "https://jeffkreeftmeijer.com/ox-html-markdown-style-footnotes/";
license = licenses.gpl3;
platforms = platforms.all;
};
}
The derivation only sets some general information about the package, like the name, file URL and fingerprint2.
The trivialBuild function takes care of the rest.
This example uses the fetchurl fetcher, which could be swapped out for a more sophisticated option like fetchgit, fetchFromGitea or fetchFromGithub. However, with this package being contained in a single file, the simplest option will suffice.
Finally, update the flake to include the newly-added derivation3:
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
flake-utils.url = "github:numtide/flake-utils";
};
outputs = { nixpkgs, flake-utils, ... } :
flake-utils.lib.eachDefaultSystem (system:
let
pkgs = import nixpkgs { inherit system; };
in
{
devShells.default = pkgs.mkShell {
buildInputs = with pkgs; [
((emacsPackagesFor emacs-nox).emacsWithPackages(epkgs: [
epkgs.evil
(epkgs.callPackage ./ox-html-markdown-style-footnotes.nix {})
]))
];
};
});
}
To determine if an Emacs package is available through Nixpkgs, use search.nixos.org, or the
nix searchcommand:nix search nixpkgs emacsPackages.evil
* legacyPackages.aarch64-darwin.emacsPackages.evil (20231106.1213) * legacyPackages.aarch64-darwin.emacsPackages.evil-anzu (20220911.1939) * legacyPackages.aarch64-darwin.emacsPackages.evil-args (20220125.1626) * legacyPackages.aarch64-darwin.emacsPackages.evil-avy (20150908.748) ...
↩︎To get the
sha256value, simply omit it when running for the first time and take the correct value from the output:warning: found empty hash, assuming 'sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=' error: hash mismatch in fixed-output derivation '/nix/store/144z7a0c6jckqrkrmdnaqdfwi37vqs8m-ox-html-markdown-style-footnotes.el.drv': specified: sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= got: sha256-S+lzFpGY44OgXAeM9Qzdhvceh8DvvOFiw5tgXoXDrsQ=↩︎In a pinch, the derivation can also be placed directly in the flake, as it’s just a function:
↩︎{ inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; flake-utils.url = "github:numtide/flake-utils"; }; outputs = { nixpkgs, flake-utils, ... } : flake-utils.lib.eachDefaultSystem (system: let pkgs = import nixpkgs { inherit system; }; in { devShells.default = pkgs.mkShell { buildInputs = with pkgs; [ ((emacsPackagesFor emacs-nox).emacsWithPackages(epkgs: [ epkgs.evil (epkgs.trivialBuild { pname = "ox-html-markdown-style-footnotes"; version = "0.2.0"; src = fetchurl { url = "https://raw.githubusercontent.com/jeffkreeftmeijer/ox-html-markdown-style-footnotes.el/0.2.0/ox-html-markdown-style-footnotes.el"; sha256 = "sha256-S+lzFpGY44OgXAeM9Qzdhvceh8DvvOFiw5tgXoXDrsQ="; }; meta = with lib; { description = "Markdown-style footnotes for ox-html.el"; homepage = "https://jeffkreeftmeijer.com/ox-html-markdown-style-footnotes/"; license = licenses.gpl3; platforms = platforms.all; }; }) ])) ]; }; }); }