# How to Configure twist.nix to Use MELPA Recipes: A Complete Nix Flake Guide

> Learn to configure twist.nix for MELPA recipes. Add MELPA as a non-flake input and register it in your twist.nix config for seamless integration. Get the complete Nix Flake guide.

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

---

**Configure twist.nix to use MELPA recipes by declaring the MELPA repository as a non-flake input in your `flake.nix` and registering it with `type = "melpa"` in your twist.nix configuration, pointing the `path` attribute to the `<input>/recipes` directory.**

twist.nix builds reproducible Emacs environments from *registries* that define package sources and metadata formats. To access the thousands of packages available on MELPA (the largest community-maintained Emacs Lisp Package Archive), you must configure twist.nix to use MELPA recipes by setting up a specialized registry that processes the recipe files into Nix derivations. This configuration requires declaring MELPA as a raw Git input and exposing its recipes directory through the registry schema.

## Understanding the MELPA Registry Type

In twist.nix, a **registry** is a structured attribute set that tells the package manager how to locate and interpret package definitions. MELPA registries use the specific type `"melpa"`, which triggers specialized processing logic distinct from ELPA or manual archives.

When you set `type = "melpa"`, twist.nix invokes the inventory logic in `pkgs/emacs/data/inventory/melpa.nix` (lines 19-21). This module reads each recipe file from the configured path, calls `lib.expandMelpaRecipeFiles` from `pkgs/build-support/default.nix` to resolve file patterns like `"*.el"`, and generates derivations using `lib.flakeRefAttrsFromMelpaRecipe` to fetch upstream sources. The conditional dispatcher in `pkgs/emacs/data/inventory/default.nix` automatically routes MELPA-type registries to this implementation.

## Step 1: Add MELPA as a Non-Flake Input

MELPA is a standard Git repository containing recipe files, not a Nix flake. You must declare it with `flake = false` to access its raw contents without Nix attempting to evaluate `outputs`.

Add the MELPA input to your `flake.nix` as demonstrated in `test/flake.nix` (lines 13-16):

```nix
{
  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
    twist.url = "github:emacs-twist/twist.nix";
    
    # MELPA repository (not a flake)

    melpa = {
      url = "github:melpa/melpa";
      flake = false;   # Required because MELPA isn't a flake

    };
  };
  
  # ... outputs definition

}

```

The `flake = false` attribute is essential. Without it, Nix expects MELPA to provide Nix outputs, which it does not. This declaration makes the repository available under `inputs.melpa.outPath` in your outputs function.

## Step 2: Define the MELPA Registry

Once MELPA is available as an input, expose its recipes directory to twist.nix by adding a registry entry with three required attributes: `name`, `type`, and `path`.

In your twist.nix configuration module (following the pattern in `test/twist.nix`, lines 26-30), define the registry:

```nix
{ inputs, pkgs, ... }:
{
  registries = [
    {
      name = "melpa";
      type = "melpa";
      path = inputs.melpa.outPath + "/recipes";
    }
    # ... other registries (e.g., ELPA, nongnu ELPA)

  ];
}

```

The `path` must point specifically to the `recipes` subdirectory containing individual recipe files (e.g., files named `magit`, `use-package`, etc.) that define package sources and file inclusion patterns.

## Complete Configuration Example

Here is a minimal, production-ready `flake.nix` that demonstrates the full integration from inputs to environment build:

```nix
{
  description = "Emacs configuration with MELPA recipes";

  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
    twist.url = "github:emacs-twist/twist.nix";
    
    melpa.url = "github:melpa/melpa";
    melpa.flake = false;
  };

  outputs = { self, nixpkgs, twist, melpa, ... }:
    let
      system = "x86_64-linux"; # Replace with your target system

      pkgs = nixpkgs.legacyPackages.${system};
    in {
      packages.${system}.emacs = twist.lib.makeEnv {
        inherit pkgs;
        registries = [
          {
            name = "melpa";
            type = "melpa";
            path = melpa.outPath + "/recipes";
          }
        ];
        initFiles = [ ./init.el ];
        extraPackages = [ "magit" "use-package" ];
      };
    };
}

```

With this configuration, running `nix build .#emacs` fetches the MELPA recipes for the requested packages, resolves their dependencies via `lib.expandMelpaRecipeFiles`, and builds them from source according to the specifications in `pkgs/emacs/data/inventory/melpa.nix`.

## Summary

- **Add MELPA as a non-flake input** using `flake = false` in your `flake.nix` to access raw recipe files without Nix evaluation.
- **Declare a MELPA registry** with `type = "melpa"` and `path = inputs.melpa.outPath + "/recipes"` in your twist.nix configuration to enable recipe parsing.
- **The registry type triggers automatic processing** via `pkgs/emacs/data/inventory/melpa.nix`, which uses `lib.expandMelpaRecipeFiles` from `pkgs/build-support/default.nix` to resolve file patterns.
- **Packages become available immediately** after configuration by referencing them in `extraPackages` or your `init.el`, with builds determined by the lock file state of the MELPA input.

## Frequently Asked Questions

### Why must I set `flake = false` for the MELPA input?

MELPA is a standard Git repository containing Emacs Lisp recipe files, not a Nix flake with `outputs` defined. Setting `flake = false` tells Nix to treat it as a plain source repository, making it available under `inputs.melpa.outPath` without evaluating it as a Nix package set. This provides access to the raw `recipes` directory that twist.nix parses to generate package derivations.

### Can I use multiple package archives alongside MELPA?

Yes. The `registries` list accepts multiple entries. You can combine MELPA with GNU ELPA, nongnu ELPA, or custom registries by adding additional attribute sets with their respective `type` values (e.g., `type = "elpa"` for GNU ELPA). Each registry processes independently, allowing you to install packages from MELPA, GNU ELPA, and local sources in the same Emacs environment.

### How do I override files listed in a MELPA recipe?

Use the `inputOverrides` attribute in your twist.nix configuration to modify specific packages. For example, to remove a problematic file from the `bbdb` package:

```nix
inputOverrides = {
  bbdb = _: super: {
    files = builtins.removeAttrs super.files [ "bbdb-notmuch.el" ];
  };
};

```

This overrides the file list generated by `lib.expandMelpaRecipeFiles` for that specific package only, without modifying the upstream recipe.

### What happens if a MELPA recipe references a repository that changes?

twist.nix generates fixed-output derivations based on the commit hash captured in your flake lock file. When you update your flake inputs using `nix flake update`, the lock file records the new state of the MELPA recipes and the specific upstream source commits they reference. Until you update, the build remains reproducible, using the exact source versions defined in the lock file regardless of upstream changes.