I have this by default in my auto-mode-alist:

("\\.js\\'" . javascript-mode)

(even with emacs -Q). I'd like to substitute js2-mode for javascript-mode. Of course, I could use assq-delete-all and then add-to-list again, but I'm wondering whether there isn't a better way.

Edit: I explicitly do not want to use Customize, I prefer crafting my init.el myself.


Use setf to change the value in place:

(setf (cdr (rassoc 'javascript-mode auto-mode-alist)) 'js2-mode)

If you want to replace a value in the list, then setf is the generalized machinery you need to do so. For the more idiomatic way to deal with the auto-mode-alist, see @Drew's answer (and his explanation of shadowing).


While @Dan's answer is a perfectly fine solution, it is unnecessary. One of the reasons Emacs uses an alist here is that with an alist you can simply add a new element to the front of the list and it will shadow matches further down the list.

(add-to-list 'auto-mode-alist '("\\.js\\'" . js2-mode))
  • 7
    Admittedly, it does not answer the question of how to replace. Its point is that you do not need to replace (unless you have some other need than what you described).
    – Drew
    Nov 11 '14 at 22:19
  • 1
    Exactly. Still, in my book this counts as a solution (even if I do not like it).
    – mbork
    Nov 11 '14 at 22:27
  • 1
    +1. It's the less-convoluted solution for working with this alist than the setf option, but the latter gets to the question of how to replace elements rather than shadow them.
    – Dan
    Nov 11 '14 at 23:12
  • 2
    the question wasn't really about replacing in the technical sense but rather changing in the higher-level sense. Nov 12 '14 at 0:43
  • 2
    This will always work no matter if the cons is in pure space or will be removed in some future version.
    – politza
    Nov 30 '16 at 20:52

The fastest way to actually change the cons cell is probably setcdr

setcdr is a built-in function in `C source code'.

(setcdr CELL NEWCDR)

Set the cdr of CELL to be NEWCDR.  Returns NEWCDR.

It's worth noting that setf isn't available in older Emacsen, but setcdr is.

*** Welcome to IELM ***  Type (describe-mode) for help.
ELISP> (setq tmp '((one . 1) (two . 2) (three . 4)))
((one . 1)
 (two . 2)
 (three . 4))

ELISP> (setcdr (assq 'three tmp) 3)
3 (#o3, #x3, ?\C-c)
ELISP> tmp
((one . 1)
 (two . 2)
 (three . 3))
  • Do you happen to know which version of Emacs added setf?
    – dshepherd
    Nov 6 '18 at 17:47
  • 1
    @dsheperd not off-hand, no. Why do you need to know? I would say any emacs that should be targeted for new development will have setf, but there might not be handling for it for the kind of data you want to set. They're called generalized variables. Nov 6 '18 at 20:10
  • I wanted to know if it was ok to use setf in some new code, but as you said it turns out there was no generalised variable for what I wanted until too recent a version anyway.
    – dshepherd
    Nov 7 '18 at 8:40

The OP asks for a solution which handles alists that have string keys. To handle that, see this question. If by chance you only need to handle alists with symbol keys, then as of Emacs 25 you can use:

(setf (alist-get <key> <alist>) <value>)

to replace a cdr. If you have access to Emacs 26, this technique does work with string keys, as follows:

(setf (alist-get "\\.js\\'" auto-mode-alist nil nil #'equal) 'js2-mode)

Note that there are also other ways in Emacs 26 to handle string keys; see this question as mentioned above.

  • (setf (alist-get "\\.js\\'" auto-mode-alist nil nil #'equal) 'js2-mode) should work (requires Emacs 26 though).
    – npostavs
    Feb 3 '18 at 13:45
  • @RadonRosborough: there is an edit feature. Consider to fix you answer.
    – antonio
    Feb 27 '18 at 21:41
  • You are using alist-get with the string "\\.js\\'", but alist-get is based on assq, so it won't work with a string as you claim in your answer.
    – antonio
    Mar 2 '18 at 5:22
  • @antonio Oh yes, you are entirely correct. I had not realized that the question as posted actually does require a solution which handles string keys. I'll make the edit, thanks! Mar 2 '18 at 19:34

If you know you won't use javascript-mode ever again let auto-mode-alist untouched and add to your init.el

  (defalias 'javascript-mode 'js2-mode "Some handy explanation goes here.")
  • 1
    Actually, there is no javascript-mode, really: javascript-mode is only an alias for js-mode (by default) and it was done this way specifically so that users could do like you suggest if they prefer js2-mode (without losing the ability to use js-mode if they want to).
    – Stefan
    May 17 '17 at 13:14
  • I derived my answer from habit of aliasing for cperl-mode and nxml-mode. So what would do the trick here? (defalias 'js-mode 'js2-mode)?
    – Matthias
    May 17 '17 at 13:22
  • 1
    You misunderstood me. I'm saying that your answer is exactly right and doesn't prevent you from using "javascript-mode" since what you call by that name is really js-mode (contrary to what happens for perl-mode, for instance).
    – Stefan
    May 17 '17 at 13:25
  • Got it... (casual javascript-mode user here)
    – Matthias
    May 17 '17 at 13:29

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.