dash.el: A modern list API for Emacs Lisp
A modern list library for Emacs
At a glance
- What is it?
- dash.el gives Emacs Lisp developers a compact collection of list operations without requiring `'cl`. It suits packages that need readable transformations, reductions, filtering, and anaphoric macros.
- Who is it for?
- Adopt dash.el for Emacs Lisp packages that repeatedly transform, filter, slice, or reduce lists and value a consistent prefixed API without adding a `'cl` dependency. Do not adopt it merely to replace every conventional loop, especially if the added package dependency is not justified.
- Can I use it commercially?
- Yes, with conditions. GPL-3.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
- Is it still maintained?
- Yes. The repository last received commits 17 days ago.
- What is it written in?
- Mainly Emacs Lisp, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Why dash.el fits Emacs package development
dash.el addresses the readability burden of expressing common list operations directly in Emacs Lisp. Filtering, mapping, slicing, indexing, replacing, and reducing lists can otherwise require a mixture of loops, recursion, and built-in functions. Dash places those operations behind one naming convention: public functions begin with `-`, while anaphoric macros use `--`. The result is not a general-purpose collection framework. Its scope is list processing, which makes it relevant to Emacs package authors who parse configuration, transform search results, update data tables, or build derived collections.
The library explicitly does not require `'cl`. That is a meaningful constraint for package authors deciding whether a utility belongs in a broader Emacs installation. Avoiding a second list library can reduce coupling when the code needs only the operations Dash already provides. It does not mean Dash supplies every sequence abstraction a project might need. The documented surface remains centered on lists and selected table-shaped data.
The prefix also makes calls recognizable at call sites. A form such as `-filter`, `-take`, or `-reduce` communicates the operation without requiring the reader to infer it from a larger block of control flow. This can be especially helpful in configuration code and package internals where list transformations are often short and frequent.
The function and anaphoric macro model in dash.el
Dash separates transformation functions from expression-oriented macros. `-map` accepts a function and applies it to each element. `--map` instead evaluates a form with the local variable `it` bound to the current element. The README compares these two forms directly:
(-map (lambda (n) (* n n)) '(1 2 3 4)) ; Normal version.
(--map (* it it) '(1 2 3 4)) ; Anaphoric version.The first form accepts a conventional function. The second removes the lambda while retaining a local name for the current value. Dash does not document `it` as a general-purpose variable for unrelated code. In an anaphoric macro call, it is the temporary binding that makes the expression possible.
The catalog also separates several behaviors that are easy to conflate. Mapping functions collect transformed results, sublist functions select elements, list-to-list functions return modified copies, and reductions return one accumulated value. There are left-to-right and right-to-left reductions, reductions with an explicit initial value, partial reductions, counting, sums, products, prefixes, and suffixes. The naming convention exposes these distinctions through names such as `-reduce-from`, `-reduce-r-from`, `-reductions`, and `-reductions-r`.
This organization makes the library more than a collection of aliases for `mapcar` or `delete`. The breadth of documented operations lets package code select a narrow operation rather than implement filtering, indexing, and reduction through one general-purpose loop.
Installing dash.el and declaring the package dependency
The README lists GNU ELPA, GNU-devel ELPA, and MELPA as installation sources. For a configured Emacs package archive containing `dash`, invoke the standard interactive package command and enter the package name when prompted:
M-x package-install RET dash RETThis uses Emacs's package installation interface rather than a shell package manager. The README points to the Emacs manual section named `(emacs) Package Installation` for the package system itself. If package archives are unavailable or if a project manages its `load-path` directly, the README also says that `dash.el` can be placed somewhere in `load-path`.
A package should declare its dependency rather than relying only on a user's interactive installation. The README gives this library-header form:
;; Package-Requires: ((dash "2.20.0"))The quoted version in this example is also the latest listed release. Package managers can use that header when resolving dependencies, although the README does not document a project-specific upgrade or rollback procedure. For an existing checkout, repository-level development commands are defined in the Makefile, but the standard user-facing route remains `package-install`.
A first dash.el transformation in an Emacs package
Start with a function call when the transformation already exists. The README provides a conventional square function and then applies it through `-map`:
(defun my-square (n)
"Return N multiplied by itself."
(* n n))
(-map #'my-square '(1 2 3 4))The function computes `(* n n)` for each element. In an interactive Emacs Lisp session, this form can be evaluated with the normal evaluation commands after `dash.el` is on `load-path`; the README does not prescribe a separate Dash runner.
For short inline transformations, the anaphoric form is more compact:
(--map (* it it) '(1 2 3 4))Here, `it` refers to the current list element inside the macro body. Both mapping forms collect results in order and return a new list according to the README's description. A named function is clearer when the logic is substantial or reused. `--map` is most suitable when the expression remains local and obvious to a reader of that package.
The README also offers optional editor integration. Calling `global-dash-fontify-mode` enables `dash-fontify-mode` in Emacs Lisp buffers, while `dash-register-info-lookup` makes Dash symbols available through `info-lookup-symbol`. These features affect symbol presentation and documentation lookup. They are optional and separate from list operations.
Where dash.el is the wrong level of abstraction
Dash is not a substitute for designing clearer data structures when a package repeatedly traverses a large, nested structure. Its documented interface is list-oriented, and the examples emphasize returning new lists, selecting sublists, and reducing values. If an application needs queues, maps with lookup semantics, sets, or lazy sequences, the README does not document those abstractions here. Adding another collection library would be a separate design decision.
There is also a readability trade-off in using `--` macros everywhere. An inline form can be concise, but a long `--map` expression with several operations can become difficult to inspect. The named-function version of `-map` costs more text while making behavior reusable and testable outside the macro call. Package authors should choose the shorter form based on local complexity rather than treating anaphoric syntax as a default.
The library does not claim to remove every dependency or every use of conventional Emacs Lisp. It states specifically that no `'cl` is required. That makes it relevant when avoiding `'cl` matters, but it should not be read as a promise that all package dependencies disappear. A code review still needs to compare the benefit of the new API with the cost of shipping another dependency.
Conventional Emacs Lisp as the practical alternative
The real alternative is ordinary Emacs Lisp implemented with explicit functions, loops, and existing language facilities. That approach does not introduce a prefixed library or a package dependency. It can also be easier for readers who do not know Dash's macro conventions, especially in a small file where only one or two list operations are needed.
Dash takes a different approach by packaging operations as a stable, discoverable vocabulary. Conventional code can express a transformation directly, while Dash makes common operations visible through names such as `-map`, `-filter`, `-slice`, and `-mapcat`. Its range of selectors and indexed updates also removes repeated ad hoc index calculations from package code.
The trade-off is API coupling. Once a package uses Dash, changing to another list approach may touch several call sites and alter its package requirements. A small extension that performs one simple list traversal may have little reason to accept that dependency. A package with repeated filtering, transformation, table-column selection, and reduction is the better fit because the library's catalog maps directly to its recurring operations.
dash.el release state, licensing, and upgrade scope
The repository is not archived, and its last push was on 2026-10-06. The listed releases include 2.20.0 on 2025-03-12, 2.19.1 on 2021-08-26, and 2.19.0 on 2021-07-08. This supports treating the repository as receiving development, but the release cadence is not uniform. Consumers should not assume that every recent repository change corresponds to a new package release.
The repository identifies its license as GPL-3.0, and the repository Makefile states that the program may be redistributed or modified under the terms of the GNU General Public License. That is a project fact, not legal advice. A distributor must still review the included `LICENSE` and package terms for its own compliance obligations.
Based on the repository layout, most of the runtime library is concentrated in `dash.el`. Development definitions and examples are separate under `dev/`, while documentation is represented by Texinfo files, templates, and `doc/`. This separation gives maintainers a compact dependency for end users while retaining dedicated files for tests, generated documentation, and development metadata. The README does not specify a migration policy from one Dash version to another, so upgrades should be checked against the `NEWS.md` changes and the dependency constraints declared by consuming packages.
Editorial conclusion
Adopt dash.el for Emacs Lisp packages that repeatedly transform, filter, slice, or reduce lists and value a consistent prefixed API without adding a `'cl` dependency. Do not adopt it merely to replace every conventional loop, especially if the added package dependency is not justified. Check your supported Emacs and package environments first, then verify that `-map`, `--map`, and the reduction functions produce the list order and initial-value behavior required by your code. For a new dependency on version 2.20.0, the package header is the most specific integration boundary.
Frequently asked questions
How do I install dash.el in Emacs?
Invoke `M-x package-install`, enter `dash`, and confirm the selection. The README lists GNU ELPA, GNU-devel ELPA, and MELPA as available package sources.
Does dash.el require Emacs Common Lisp support?
No. The README explicitly describes Dash as a modern list API for Emacs with no `'cl` required.
When should I use `-map` instead of `--map` in dash.el?
Use `-map` with a function for substantial or reusable transformations. Use `--map` when a short expression benefits from having the current element bound to `it`.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/magnars-dash-el)Was this useful?