cabal-edit: Cabal utility

[ development, mit, program ] [ Propose Tags ]

A utility for managing Hackage dependencies from the command line.

[Skip to Readme]
Versions [faq]
Change log
Dependencies base (>=4.12 && <5.0), bytestring (==0.10.*), Cabal (>=3.0 && <4.0), containers (==0.6.*), directory (==1.3.*), filepath (==1.4.*), Glob (==0.10.*), hackage-db (==2.1.*), optparse-applicative (==0.15.*), process (==1.6.*), store (==0.7.*), time (>=1.8 && <1.11) [details]
License MIT
Copyright 2020 Stephen Diehl
Author sdiehl
Revised Revision 1 made by sdiehl at 2020-07-21T12:04:47Z
Category Development
Bug tracker
Source repo head: git clone
Uploaded by sdiehl at 2020-07-21T09:52:15Z
Distributions NixOS:
Executables cabal-edit
Downloads 59 total (9 in the last 30 days)
Rating (no votes yet) [estimated by Bayesian average]
Your Rating
  • λ
  • λ
  • λ
Status Hackage Matrix CI
Docs not available [build log]
Last success reported on 2020-07-21 [all 2 reports]


Note: This package has metadata revisions in the cabal description newer than included in the tarball. To unpack the package including the revisions, use 'cabal get'.

Maintainer's Corner

For package maintainers and hackage trustees

Readme for cabal-edit-

[back to package description]


Cabal CI Stack CI

This is an extension to Haskell's package manager Cabal to allow you to add, remove, and upgrade dependencies by modifying your cabal file from the command line. This behaves similar to install --save commands in other package managers.



For example to setup a new project one often wants to add common dependencies like text and aeson. We can use cabal-edit to automatically append these to our dependency list and deduce the latest versions from Hackage.

$ cabal init --lib --cabal-version=3.0    

$ cabal-edit add aeson                
Adding dependency: aeson ^>=1.5 to sample.cabal

$ cabal-edit add text 
Adding dependency: text ^>=1.2 to sample.cabal

If we want to depend on a specific version of aeson, we can pass this explicitly as an argument.

$ cabal-edit add aeson==

Multiple packages can be passed to the add command at once. For example:

$ cabal-edit add base bytestring aeson text process filepath directory mtl transformers protolude
Adding latest dependency: base ^>=4.14 to sample.cabal
Adding latest dependency: bytestring ^>=0.10 to sample.cabal
Adding latest dependency: aeson ^>=1.5 to sample.cabal
Adding latest dependency: text ^>=1.2 to sample.cabal
Adding latest dependency: process ^>=1.6 to sample.cabal
Adding latest dependency: filepath ^>=1.4 to sample.cabal
Adding latest dependency: directory ^>=1.3 to sample.cabal
Adding latest dependency: mtl ^>=2.2 to sample.cabal
Adding latest dependency: transformers ^>=0.5 to sample.cabal
Adding latest dependency: protolude ^>=0.3 to sample.cabal

Note: Dependency modification will happen over the library stanza of your Cabal file, and not the executable sections.


The upgrade command can be used to safely manipulate the version bounds for a given library. For instance if one has a simple dependency on text for 1.0 version range, like as follows:

    exposed-modules:  MyLib
    default-language: Haskell2010
        base >= 4.14 && <=5.0,
        text ^>= 1.0

We can bump the bound of this library to upgrade it to allow the latest version from Hackage. We simply pass the upgrade command the name of the package (i.e. text) and it will automatically figure out the appropriate version range for the upgrade including previously version ranges. The resulting version ranges will always have an upper bound and will conform to Hackage PVP standards.

$ cabal-edit upgrade text
Upgrading bounds for text to 1.3

This will produce the following modified Cabal file.

    exposed-modules:  MyLib
    default-language: Haskell2010
        base >=4.14 && <=5.0,
        text >=1.0 && <=1.3


upgradeall behaves like upgrade but performs the version bound bump for all available dependencies. This sets the upper bounds for all dependencies to the latest available version on Hackage.

$ cabal-edit upgradeall
Upgrading bounds for Cabal to 3.3
Upgrading bounds for aeson to 1.6
Upgrading bounds for base to 4.15
Upgrading bounds for bytestring to 0.11
Upgrading bounds for ghc to 8.11
Upgrading bounds for text to 1.3


Remove will remove a given dependency from the file completely.

$ cabal-edit remove microlens
Removing depndency on microlens


The Hackage database can be queried from the command line to search for all available versions to use with the list command.

$ cabal-edit list filepath


The format command will canonicalise the Cabal into by parsing it and running it through the pretty printer again.

$ cabal-edit format
Formatting: sample.cabal


The extensions command will enumerate all the default extensions enabled for the given library. This is useful if you wish to add these headers to files within the project.

$ cabal-edit extensions

{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}


The lint command will detect common problems with your version bounds and recommend package upgrades when available.

$ cabal-edit lint 
aeson : Consider upgrading major bound to latest version 1.6
text : Consider upgrading major bound to latest version 1.3


The latest command will return the dependency string for adding the latest version of a given package.

$ cabal-edit latest aeson
aeson ^>=1.5


cabal-edit uses a cache of Hackage package versions internally. This is normally built on first run and whenever the package database is older than 30 days. If you wish to manually rebuild it after running cabal update then run:

$ cabal-edit rebuild


Download this repository.

$ git clone
$ cd cabal-edit

Then install either with Stack, Cabal or Nix.

$ stack install 
$ cabal install --installdir=/home/$USER/.local/bin
$ nix-build -A cabal-edit

Note: This library links directly against Cabal, so you must be using the same version of Cabal you intend to compile your package against. It is reccomened to use Cabal > 3.0 to support modern versioning schemes.

Shell Completions

We can tab complete on the Hackage package index we install the local completions for you shell. Run one of the following commands to generate the shell completer appropriate to your shell. Then add the output to one of ~/.zshrc, ~/.bashrc or ~/.config/fish/

$ cabal-edit --zsh-completion-script cabal-edit
$ cabal-edit --bash-completion-script cabal-edit
$ cabal-edit --fish-completion-script cabal-edit

This will completion against the Hackage database prefixed by name.

$ cabal-edit add gh
zsh: do you wish to see all 103 possibilities (15 lines)?
$ cabal-edit add ghc-pa
ghc-parmake  ghc-parser   ghc-paths


    local CMDLINE
    local IFS=$'\n'
    CMDLINE=(--bash-completion-index $COMP_CWORD)

    for arg in ${COMP_WORDS[@]}; do
        CMDLINE=(${CMDLINE[@]} --bash-completion-word $arg)

    COMPREPLY=( $(cabal-edit "${CMDLINE[@]}") )

complete -o filenames -F _cabal-edit cabal-edit


#compdef cabal-edit

local request
local completions
local word
local index=$((CURRENT - 1))

request=(--bash-completion-enriched --bash-completion-index $index)
for arg in ${words[@]}; do
  request=(${request[@]} --bash-completion-word $arg)

IFS=$'\n' completions=($( cabal-edit "${request[@]}" ))

for word in $completions; do
  local -a parts

  # Split the line at a tab if there is one.
  IFS=$'\t' parts=($( echo $word ))

  if [[ -n $parts[2] ]]; then
     if [[ $word[1] == "-" ]]; then
       local desc=("$parts[1] ($parts[2])")
       compadd -d desc -- $parts[1]
       local desc=($(print -f  "%-019s -- %s" $parts[1] $parts[2]))
       compadd -l -d desc -- $parts[1]
    compadd -f -- $word


 function _cabal-edit
    set -l cl (commandline --tokenize --current-process)
    # Hack around fish issue #3934
    set -l cn (commandline --tokenize --cut-at-cursor --current-process)
    set -l cn (count $cn)
    set -l tmpline --bash-completion-enriched --bash-completion-index $cn
    for arg in $cl
      set tmpline $tmpline --bash-completion-word $arg
    for opt in (cabal-edit $tmpline)
      if test -d $opt
        echo -E "$opt/"
        echo -E "$opt"

complete --no-files --command cabal-edit --arguments '(_cabal-edit)'


Since this library works directly with the PackageDescription data structure it cannot handle Cabal files in their full generality. Instead we directly manipulate the internal structure used to represent the Cabal file which is not capable of representing all surface constructs. If your Cabal file currently uses:

  • Common stanzas
  • Conditional blocks
  • Preprocessor definitions

These constructs will be compiled into the PackageDescription and inlined if you use cabal-edit. This makes cabal-edit useful for small beginning projects and ones that don't use advanced Cabal features.


MIT License Copyright (c) 2020, Stephen Diehl