# Understanding the emacsPackage Option in twist.nix Configuration

> Learn how to use the emacsPackage option in twist.nix to specify your Emacs derivation for reproducible builds and custom environments. Pin versions easily.

- Repository: [Emacs Twist/twist.nix](https://github.com/emacs-twist/twist.nix)
- Tags: deep-dive
- Published: 2026-03-01

---

**The `emacsPackage` option in twist.nix lets you specify which Emacs derivation to use when building your Emacs Lisp package set, enabling version pinning, custom builds, and reproducible environments.**

The `emacsPackage` argument is a core configuration option in the [emacs-twist/twist.nix](https://github.com/emacs-twist/twist.nix) repository. It controls which Emacs binary Twist uses as the foundation for your entire Emacs configuration, affecting how packages are compiled and which built-in libraries are available.

## What is the emacsPackage Option?

`emacsPackage` is a configurable argument defined in `pkgs/emacs/default.nix` that determines which Emacs derivation Twist should use when building and managing Emacs Lisp packages.

If you omit this option, Twist falls back to the default Emacs package provided by your Nixpkgs set:

```nix
emacsPackage ? pkgs.emacs,

```

*(Source: [`pkgs/emacs/default.nix` line 6](https://github.com/emacs-twist/twist.nix/blob/master/pkgs/emacs/default.nix#L6))*

This default ensures that Twist works out-of-the-box with standard Nixpkgs channels, but the option exists precisely so you can override it when you need specific Emacs versions or custom builds.

## Why Use the emacsPackage Option?

The `emacsPackage` option exists to solve three specific problems in Emacs environment management:

### Version Control

You can pin a specific Emacs version (e.g., `29.1`, `master`, or a custom snapshot) so that all generated package derivations are built against that exact version. This prevents unexpected breakages when Nixpkgs updates its default Emacs package.

### Custom Builds

You may want to use a patched or locally built Emacs (e.g., with different `--with-modules` flags or native compilation settings). Supplying your own derivation makes Twist honor those customizations throughout the dependency tree.

### Testing and CI

The test suites (`test/twist.nix`, `test/flake.nix`) explicitly inject different `emacsPackage` values to verify that Twist works with multiple Emacs builds:

```nix
emacsPackage = emacs-ci.packages.${system}.emacs-snapshot;

```

*(Source: [`test/flake.nix` line 61](https://github.com/emacs-twist/twist.nix/blob/master/test/flake.nix#L61))*

## How to Configure emacsPackage in twist.nix

### Overriding with a Specific Emacs Version (Flake)

When using Twist in a Flake-based configuration, you can override `emacsPackage` to use a specific Emacs version from an external source like `emacs-ci`:

```nix
{
  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
    twist = {
      url = "github:emacs-twist/twist.nix";
      inputs.nixpkgs.follows = "nixpkgs";
    };
    # Use a specific Emacs snapshot from the emacs-ci overlay

    emacs-ci = {
      url = "github:nix-community/emacs-ci";
      inputs.nixpkgs.follows = "nixpkgs";
    };
  };

  outputs = { self, nixpkgs, twist, emacs-ci, ... }:
    let
      system = "x86_64-linux";
      pkgs = import nixpkgs { inherit system; };
    in {
      packages.${system}.myEmacsEnv = twist.lib.mkTwist {
        pkgs = pkgs;
        lockDir = ./twist-lock;
        initFiles = [ ./init.el ];
        # <<< The important part >>>

        emacsPackage = emacs-ci.packages.${system}.emacs-snapshot;
      };
    };
}

```

*This pattern is used in the official test suite to validate against bleeding-edge Emacs builds.*

### Using a Custom Emacs Derivation

For locally patched or custom-configured Emacs builds, pass your own derivation:

```nix

# custom-emacs.nix

{ pkgs ? import <nixpkgs> { } }:
pkgs.stdenv.mkDerivation {
  name = "emacs-custom-29.2";
  src = pkgs.fetchFromGitHub {
    owner = "emacs-mirror";
    repo  = "emacs";
    rev    = "emacs-29.2";
    sha256 = "sha256-…";
  };
  # …standard Emacs build steps, possibly with extra configure flags…

}

```

```nix

# twist.nix (your configuration)

{
  pkgs = import <nixpkgs> { };
  lockDir = ./twist-lock;
  initFiles = [ ./init.el ];
  emacsPackage = import ./custom-emacs.nix { inherit pkgs; };
}

```

*Now every package generated by Twist will be compiled against your locally patched Emacs 29.2.*

### Using the Default Emacs

If you omit the `emacsPackage` argument entirely, Twist automatically uses the Emacs provided by your Nixpkgs channel:

```nix
{
  pkgs = import <nixpkgs> { };
  lockDir = ./twist-lock;
  initFiles = [ ./init.el ];
  # No `emacsPackage` → defaults to pkgs.emacs

}

```

*This is the simplest configuration and works well when you don't need specific Emacs versions.*

## Technical Implementation Details

Inside Twist, the `emacsPackage` argument is stored as `self.emacs` and exposed as the top-level attribute `emacs` of the generated package set:

```nix
inherit emacsPackage;

# ...

self.emacs = emacsPackage;

```

Twist also consults the Emacs version string to determine which built-in packages to include. For example, `use-package` is only added for Emacs versions older than 29:

```nix
extraPackages ?
  if builtins.compareVersions emacsPackage.version "29" > 0
  then [] else ["use-package"],

```

*(Source: [`pkgs/emacs/default.nix` lines 17-19](https://github.com/emacs-twist/twist.nix/blob/master/pkgs/emacs/default.nix#L17-L19))*

This version-aware behavior ensures that your configuration automatically adapts to the capabilities of your chosen Emacs build.

## Summary

- **`emacsPackage`** is the configuration option that determines which Emacs derivation Twist uses as the foundation for your package set.
- **Default behavior** uses `pkgs.emacs` from your Nixpkgs channel when no override is specified.
- **Version pinning** allows you to lock your entire configuration to a specific Emacs version (e.g., 29.1, master, or snapshots).
- **Custom builds** enable you to use patched or locally built Emacs derivations with specific configure flags.
- **Internal usage** stores the value as `self.emacs` and uses it for version-aware package selection (e.g., excluding `use-package` on Emacs 29+).

## Frequently Asked Questions

### How do I pin a specific Emacs version with emacsPackage?

Pass a specific Emacs derivation to the `emacsPackage` argument when calling `twist.lib.mkTwist`. You can source this from `nix-community/emacs-ci` for snapshots or use `pkgs.emacs29` for specific releases. For example: `emacsPackage = pkgs.emacs29;` or `emacsPackage = emacs-ci.packages.${system}.emacs-snapshot;`.

### What happens if I don't specify emacsPackage?

If you omit the `emacsPackage` argument, Twist defaults to using `pkgs.emacs` from your imported Nixpkgs set. This is defined in `pkgs/emacs/default.nix` with the fallback argument `emacsPackage ? pkgs.emacs`. Your configuration will use whatever Emacs version is current in your Nixpkgs channel.

### Can I use a custom-patched Emacs with twist.nix?

Yes. You can provide any valid Emacs derivation to `emacsPackage`, including locally patched builds. Create a custom derivation using `stdenv.mkDerivation` or override the standard Emacs package, then pass it to `twist.lib.mkTwist`. This ensures all Emacs Lisp packages are compiled against your specific Emacs build flags and patches.

### Does emacsPackage affect which packages are available?

Yes, indirectly. Twist uses the Emacs version string to determine which built-in packages to include in the package set. For example, in `pkgs/emacs/default.nix`, Twist checks if `emacsPackage.version` is greater than "29" to decide whether to include `use-package` as an external package (since it's built-in for Emacs 29+).