New stuff in Emacs 30

(updated: 13 Feb, 2025) by Graham Marlow

Emacs 30.1 is near on the horizon with the most recent pretest (30.0.93) made available in late December. This post highlights some new features in the upcoming release that I find especially compelling.

If you want to know everything that's upcoming, check out the full release notes.

Native compilation enabled by default

This is huge!

Native compilation was introduced in Emacs 28 behind a configuration flag, so even though it's been around for a little while you probably aren't using it unless you compile your Emacs from source (or use a port that explicitly had it enabled). Enabling it by default brings it to more users.

This feature compiles Emacs Lisp functions to native code, offering 2-5x faster performance to the byte-compiled counterpart. The downside is an additional dependency (libgccjit) and a little extra compilation overhead when installing a package for the first time. The downsides are so minor that enabling it by default is a no-brainer.

Native (and faster) JSON support

You no longer need an external library (libjansson) to work with JSON in Emacs. On top of that, JSON parsing performance in Emacs is significantly improved (the author provides that parsing is up to 8x faster). This is all thanks to Géza Herman's contribution: I created a faster JSON parser. He summarizes his changes later in that thread:

My parser creates Lisp objects during parsing, there is no intermediate step as Emacs has with jansson. With jansson, there are a lot of allocations, which my parser doesn't have (my parser has only two buffers, which exponentially grow. There are no other allocations). But even ignoring performance loss because of mallocs (on my dataset, 40% of CPU time goes into malloc/free), I think parsing should be faster, so maybe jansson is not a fast parser in the first place.

Great stuff.

use-package version control support

You can now install packages directly from version-controlled repositories (for those packages that aren't yet in ELPA, Non-GNU ELPA or MELPA).

For example:

(use-package bbdb
  :vc (:url "https://git.savannah.nongnu.org/git/bbdb.git"
       :rev :newest))

This also means that you can opt into package updates based on commit instead of latest release (e.g. :rev :newest). I think this is actually a sleeper feature of :vc, since the default Emacs package release/update cycle can be a little wonky at times.

If you want all of your :vc packages to prefer the latest commit (instead of the latest release), you can set use-package-vc-prefer-newest to t.

Tree-sitter modes are declared as submodes

I had to read this change a few times before I grokked what it was saying. Tree-sitter modes, e.g. js-ts-mode, are now submodes of their non-tree-sitter counterpart, e.g. js-mode. That means any configuration applied to the non-tree-sitter mode also applies to the tree-sitter mode.

In other words, my .dir-locals.el settings for js-mode simply apply to js-ts-mode as well, without needing to write it explicitly. A nice quality of life change to help pare down Emacs configurations that rely on both modes (which is more common than you might think, given that non-tree-sitter modes are typically more featureful).

Minibuffer QOL improvements

Some nice quality-of-life improvements for the default Emacs completions:

  • You can now use the arrow keys to navigate the completion buffer vertically (in addition to the M-<up|down> keybindings).

  • Previous minibuffer completion selections are deselected when you begin typing again (to avoid accidentally hitting a previous selection).

  • completions-sort has a new value: historical. Completion candidates will be sorted by their order in minibuffer history so that recent candidates appear first.

Customize interface for dir-locals

There's now a customize interface for Directory Variables:

M-x customize-dirlocals

I always find myself forgetting the .dir-locals.el syntax (even though they're just lists!) so this is a surprisingly handy feature for me.

New mode: visual-wrap-prefix-mode

Now this one is cool. I'm the kind of guy who uses auto-mode for everything because I haven't bothered to figure out how Emacs line wrapping works. Everything I write hard breaks into newlines after 80 characters.

The new mode visual-wrap-prefix-mode is like auto-mode, except that the breaks are for display purposes only. I think this is incredibly useful when editing text that might be reviewed using a diffing tool, since long lines tend to display more useful diffs than a paragraph broken up with hard breaks. I'm actually pretty excited about this change, maybe it will get me to stop using (markdown-mode . (( mode . auto-fill)) everywhere.

New command: replace-regexp-as-diff

You can now visualize regular expression replacements as diffs before they're accepted. This is actually incredible.

New package: which-key

Previously a package in GNU ELPA, which-key-mode is now built-in. With which-key-mode enabled, after you begin a new command (e.g. C-x) and wait a few seconds, a minibuffer will pop up with a list of possible keybinding completions. It's a super handy tool for remembering some of the more esoteric modes.

New customizations

  • Show the current project (via project.el) in your modeline with project-mode-line.

  • Add right-aligned modeline elements via mode-line-format-right-align.

  • You can now customize the venerable yes-or-no-p function with yes-or-no-prompt.

A few Emacs Lisp changes

There are a few small, yet impactful changes around help buffers and Emacs Lisp types that I think are worth noting.

  • describe-function shows the function inferred type when available:
C-h f concat RET

(concat &rest SEQUENCES)
  Type: (function (&rest sequence) string)
  • Built-in types show their related classes:
C-h o integer RET

integer is a type (of kind ‘built-in-class’).
 Inherits from ‘number’, ‘integer-or-marker’.
 Children ‘fixnum’, ‘bignum’.
  • The byte compiler warns if a file is missing the lexical binding directive. Lexical bindings have been included in ELisp for awhile now, so it's nice to see more effort being made towards making it the default.
;;; Foo mode  -*- lexical-binding: t -*-

Read the full details

That wraps up my highlights. There's a ton more stuff included in Emacs 30.1 so I encourage you to check it out the NEWS yourself.

PS. Interested in trying out Emacs but don't know where to start? Check out my MIT-licensed configuration guide: Start Emacs.


Thanks for reading! Comment by email.