The Nix packages collection is large with over 60 000 packages. However, chances are that sometimes the package you need is not available. You must integrate it yourself.
I needed for some fonts which were not already present inside nixpkgs. In Nix, a font is distributed as a package like any other software. One of the fonts to install is Dancing Script. At the time of this writing, searching in nixpkgs doesn’t reveal any relevant match:
nix search nixpkgs dancing
Whether your system is running NixOS or just using the Nix package manager, as I do with macOS, creating a Nix package isn’t always so hard. The package we will create works for every Nix deployment. I provide the commands for Linux running NixOS and for macOS using nix-darwin. It is certainly intimidating. You must get your hands dirty and write some code. However, considering the Nix nature, the majority of us already have a few custom Nix configuration files. I’ll illustrate the process for creating and sharing a new Nix package with the community.
Fonts installation with NixOS
NixOS propose many font packages. For a font to be visible to all your applications, it must be registered inside the
fonts.fonts options list. For example, from your main
config, pkgs, ... : imports = [ ./david-framework-hardware.nix ]; fonts.enableFontDir = true; fonts.fonts = with pkgs; [ dejavu_fonts inter ];
Not every font is available from nixpkgs. This is how to install a not yet supported font inside the
fonts.fonts option list by creating our package. Once the package is ready, we publish it!
Finding an appropriate example
The NixOS documentation is confusing. It is split between multiple locations. Sometimes it lacks basic information and sometimes it goes so deep into the details that it is hard to understand. Reading the source code is a good and recommended approach to learn about the language and to customize your environment.
On every system, installing a font is about downloading it and placing it in the appropriate system location. Let’s find out how other fonts are installed. For example, the Inter typeface. Lookup
inter through the Nix search. There is a
source link that points to the package inside the nixpkgs repository:
lib, fetchzip : let version = "3.19"; in fetchzip name = "inter-$version"; url = "https://github.com/rsms/inter/releases/download/v$version/Inter-$version.zip"; postFetch = '' mkdir -p $out/share/fonts/opentype unzip -j $downloadedFile \*.otf -d $out/share/fonts/opentype ''; sha256 = "sha256-8p15thg3xyvCA/8dH2jGQoc54nzESFDyv5m47FgWrSI="; meta = with lib; homepage = "https://rsms.me/inter/"; description = "A typeface specially designed for user interfaces"; license = licenses.ofl; platforms = platforms.all; maintainers = with maintainers; [ demize dtzWill ]; ;
The package contains some metadata such as the package name, a link to the official project, and a description. The
sha256 is used by
fetchzip to download the font files. Every
.otf file is extracted from the zip archive into the
Creating a package
Looking at the Dancing Script repository, there is no download available. Instead of the
fetchzip function used to download a
.zip archive, we use the
fetchFromGitHub function to download the snapshot of a GitHub repository.
The code is organized differently, with different properties, but it achieves the same purpose. Next to your
configuration.nix file, create the
lib, fetchFromGitHub : let pname = "dancing-script"; version = "2.0"; in fetchFromGitHub name = "$pname-$version"; owner = "impallari"; repo = "DancingScript"; rev = "f7f54bc1b8836601dae8696666bfacd306f77e34"; sha256 = "dfFvh8h+oMhAQL9XKMrNr07VUkdQdxAsA8+q27KWWCA="; postFetch = '' tar xf $downloadedFile --strip=1 install -m444 -Dt $out/share/fonts/truetype fonts/ttf/*.ttf ''; meta = with lib; description = "Dancing Script"; longDescription = "A lively casual script where the letters bounce and change size slightly."; homepage = "https://github.com/impallari/DancingScript"; license = licenses.ofl; platforms = platforms.all; maintainers = with maintainers; [ wdavidw ]; ;
Once the GitHub repository is fetched, we install all the
.ttf files into the
Assuming that we are editing a
configuration.nix file collocated with the
dancing-script folder, we import the new package to
fonts.fonts option list:
config, pkgs, ... : let dancing-script = import ./dancing-script/default.nix inherit lib; fetchFromGitHub = pkgs.fetchFromGitHub; ;in imports = [ ./david-framework-hardware.nix ]; fonts.enableFontDir = true; fonts.fonts = with pkgs; [ dancing-script dejavu_fonts inter ];
Note how we satisfy the package dependencies by injecting
fetchFromGitHub when calling
import. A shorter and easier approach uses
config, pkgs, ... : let dancing-script = pkgs.callPackage ./dancing-script/default.nix ;in imports = [ ./david-framework-hardware.nix ]; fonts.enableFontDir = true; fonts.fonts = with pkgs; [ dancing-script dejavu_fonts inter ];
nixos-rebuild switch (or
darwin-rebuild switch on macOS) loads the font in the system. On Linux,
fc-list lists the fonts available in the system:
fc-list | grep dancing/nix/store/fm8y81bjhcy8p4cp32230xr78807x0ii-dancing-script-2.000/share/fonts/truetype/DancingScript-Bold.ttf: Dancing Script:style=Bold /nix/store/fm8y81bjhcy8p4cp32230xr78807x0ii-dancing-script-2.000/share/fonts/truetype/DancingScript-Regular.ttf: Dancing Script:style=Regular
Package integration with nixpkgs
Now that our package is working, the next step is to share our work with the community.
Start by forking the nixpkgs repository and clone the fork on your machine:
git clone origin https://github.com/wdavidw/nixpkgs.git cd nixpkgs
Insights on how to contribute to the project are written in
CONTRIBUTING.md. Creating a merge request to propose a new package involve 3 commits:
- creating the package Nix file
pkgs/top-level/all-packages.nixto register the package
- updating the
maintainers/maintainer-list.nixto register yourself unless already present
pkgs/data/fonts, create a new
dancing-script folder and import the
default.nix file present above.
maintainer-list.nix files as well. Their content is self-explanatory. Also, there is some sort of order inside those two files but it is not strictly enforced.
The former register our new package:
dancing-script = callPackage ../data/fonts/dancing-script ;
The later register you as a contributor:
wdavidw = name = "David Worms"; email = "[email protected]"; github = "wdavidw"; githubId = 46896; ;
githubId value is exposed by the GitHub API at
username with your GitHub handle.
dancing-script package is now registered in nixpkgs.
Testing packages from nixpkgs
Before submitting the pull request, it is possible to associate and test our Nix configuration with the local
nixpkgs repository. Run the
nixos-rebuild switch command (or
darwin-rebuild switch on macOS) with the extra
-I argument to reconfigure the machine with the local nixpkgs packages including our latest addition.
First, we update and simplify our configuration.nix file accordingly:
config, pkgs, ... : imports = [ ./david-framework-hardware.nix ]; fonts.enableFontDir = true; fonts.fonts = with pkgs; [ dancing-script dejavu_fonts inter ];
nixpkgs directory, the command to reconfigure the machine using the local nixpkgs repository is:
nixos-rebuild switch -I nixpkgs=.
The process to share the changes with the community is standard GitOps.
Changes are committed with:
git add \ maintainers/maintainer-list.nix \ pkgs/data/fonts/dancing-script/default.nix \ pkgs/top-level/all-packages.nix git commit -m 'dancing-script: init at 2.0' git push origin master
The commit message respects the guidelines found in
CONTRIBUTING.md. Go to your GitHub repository and create the pull request.
The final result was published just before this article. The merge request is visible online as “PR #166057, dancing-script: init at 2.0”. It is merged withing 24 hours and I am now an official NixOS maintainer!