Package Source Formats Supported by twist.nix: The Complete Reference

twist.nix supports seven distinct package source formats including MELPA recipes, ELPA core/external Git sources, single .el files, tarballs, archive-contents indexes, Git submodules, and EmacsMirror repositories.

twist.nix is a Nix library designed to build and manage Emacs Lisp packages with reproducible dependencies. Understanding the package source formats it accepts is essential for configuring your Emacs environment, as the library automatically detects the inventory type and selects the appropriate fetch and build implementation according to the emacs-twist/twist.nix source code.

Overview of Supported Package Source Formats

The twist.nix library ingests packages from upstream sources through seven primary distribution methods. Each format is handled by a dedicated Nix module in pkgs/emacs/data/inventory/:

  • MELPA recipe (Git): Packages described by MELPA-style recipe files pointing to Git repositories
  • ELPA external/core package (Git): ELPA packages shipping a src directory or Git URL for the whole repository
  • ELPA/MELPA archive (single .el file): Standalone Emacs Lisp files distributed as single-file archives
  • ELPA/MELPA archive (tarball): Packages distributed as compressed tarballs containing multiple files
  • Archive-contents listings: Index files from ELPA or MELPA that catalog many packages together
  • Git submodule listings: Packages defined in a .gitmodules file, typically for monorepos
  • EmacsMirror (Git): Mirrors of ELPA/MELPA hosted on GitHub, treated identically to ELPA Git sources

How twist.nix Dispatches Source Formats

The central dispatcher that selects the appropriate implementation based on the inventory's type attribute lives in pkgs/emacs/data/inventory/default.nix. This file contains a conditional chain that routes to the correct handler:


# pkgs/emacs/data/inventory/default.nix

if type == "melpa"        then import ./melpa.nix { inherit lib flakeLockData; }
else if type == "elpa"   then import ./elpa.nix { inherit lib flakeLockData; }
else if type == "archive-contents"
                         then import ./archive-contents.nix { inherit lib flakeLockData; }
else if type == "archive"
                         then import ./archive.nix { inherit lib archiveLockData; }
else if type == "gitmodules"
                         then import ./gitmodules.nix { inherit lib flakeLockData; }
else throw "Unsupported inventory type: ${type}"

When the inventory is processed, twist.nix detects the format from the directory structure and metadata files, then invokes the corresponding handler to fetch, unpack, and build the package.

Detailed Format Specifications

MELPA Recipes (Git)

MELPA-style recipes define packages through recipe files (typically *.recipe) containing repository URLs and file specifications. The implementation in pkgs/emacs/data/inventory/melpa.nix reads each recipe file and uses lib.expandMelpaRecipeFiles to enumerate the package's files before fetching the Git repository.

ELPA Core and External Packages (Git)

ELPA packages are processed by pkgs/emacs/data/inventory/elpa.nix, which parses the archive-contents file using lib.parseElpaPackages. The implementation distinguishes between:

  • Core packages: Provided by the core-src directory within your Emacs source tree
  • External packages: Containing a url attribute pointing to an external Git repository

Archive Distributions (Single Files and Tarballs)

The pkgs/emacs/data/inventory/archive.nix module handles direct URL references to archives. It supports two distribution methods:

  • Single .el files: Individual Emacs Lisp files fetched directly
  • Tarballs: Compressed archives containing complete package structures

This module builds lock entries that record type = "file" or type = "tarball" and fetches the content using fetchTree.

Archive-Contents Indexes

For bulk package management, pkgs/emacs/data/inventory/archive-contents.nix processes raw archive-contents index files from ELPA or MELPA. This handler takes a directory containing the index file and a base URL, then constructs locked sources for every entry listed in the index.

Git Submodules

The pkgs/emacs/data/inventory/gitmodules.nix module enables importing packages defined in a .gitmodules file. This is particularly useful for monorepos containing multiple Emacs packages. The implementation uses lib.readGitModulesFile to parse the submodules and lib.expandMelpaRecipeFiles to handle file expansion.

EmacsMirror Repositories

EmacsMirror sources are treated identically to ELPA Git sources and processed by the same logic in elpa.nix. These GitHub-hosted mirrors of ELPA/MELPA packages require no special configuration beyond standard ELPA Git handling.

Configuration Examples

Adding a MELPA Recipe

Create a directory containing MELPA recipe files and reference it in your inventory:


# my-packages/melpa

# Save a MELPA recipe, e.g. `my-package`:

# (name . "my-package")

# (version . "0.1")

# (doc . "A tiny example package.")

# (reqs . ())

# (type . "git")

# (url . "https://github.com/example/my-package")

# (files . ("my-package.el"))

{
  path = ./my-packages/melpa;
}

When processed, melpa.nix fetches the Git repository, expands the listed files, and makes them available as a Nix package.

Declaring an ELPA Core Package

Configure ELPA packages by specifying the Emacs source tree and core directory:

{
  # In a twist configuration (e.g. flake.nix)

  packages = {
    emacs = emacsPackage // {
      src = ./my-emacs-src;               # your Emacs source tree

      core-src = ./my-emacs-src/core;     # directory that holds core ELPA packages

    };
  };
}

elpa.nix treats entries containing a core attribute as core packages, using core-src as the source location.

Using Archive Sources

Reference single files or tarballs directly via URL:

{
  # Single .el file

  url = "https://elpa.gnu.org/packages/example-1.2.3.el";
}
{
  # Tarball archive

  url = "https://elpa.gnu.org/packages/example-1.2.3.tar";
}

archive.nix automatically detects the archive type and generates the appropriate lock entry.

Importing Git Submodules

Point to a repository containing a .gitmodules file:

{
  path = ./my-gitmodules-repo;
}

gitmodules.nix reads the configuration, fetches each submodule, and prepares the packages for building.

Summary

  • twist.nix supports seven package source formats through modular handlers in pkgs/emacs/data/inventory/
  • The dispatcher in default.nix routes to melpa.nix, elpa.nix, archive.nix, archive-contents.nix, or gitmodules.nix based on the type attribute
  • MELPA and ELPA Git sources use recipe parsing and lib.expandMelpaRecipeFiles for file enumeration
  • Archives are handled as either single .el files or tarballs with fetchTree integration
  • Git submodules enable monorepo workflows through .gitmodules parsing
  • EmacsMirror repositories work transparently with existing ELPA Git logic

Frequently Asked Questions

How does twist.nix determine which source format to use?

twist.nix detects the format by examining the inventory directory structure and the type attribute in your configuration. The dispatcher in pkgs/emacs/data/inventory/default.nix matches the type to the appropriate handler module. For example, directories containing *.recipe files trigger the MELPA handler, while directories with archive-contents files route to the ELPA handler.

Can I mix different source formats in the same configuration?

Yes. twist.nix allows you to combine multiple inventory types within a single Emacs configuration. You can reference MELPA recipes for some packages, ELPA archives for others, and Git submodules for private packages. Each inventory entry specifies its own type, and the dispatcher processes them independently through their respective implementation files.

What is the difference between ELPA core and external packages in twist.nix?

ELPA core packages are bundled with the Emacs source distribution and referenced through the core-src attribute, typically located in your Emacs source tree under a core directory. External ELPA packages are fetched from remote Git repositories via URLs listed in the archive-contents file. The elpa.nix module distinguishes between these using the presence of a core attribute or a url attribute in the package metadata.

Does twist.nix support packages from EmacsMirror?

Yes. EmacsMirror repositories are treated as standard ELPA Git sources and processed by the same logic in pkgs/emacs/data/inventory/elpa.nix. These GitHub-hosted mirrors require no special configuration beyond the standard ELPA Git handling, making them interchangeable with upstream ELPA sources in your twist.nix configuration.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →