EDIT: Changed "load" to "visit"

I want to set a variable when a specific file is visited, for example "package.json". Note I don't want to set a variable when any json file is visited, only for "package.json". What is the easiest way to achieve this.

I guess it can be done with a hook to json-mode that calls a function that sets the variable, but was wondering if there is a more idiomatic solution.

I'm looking for something similar to how it is defined in .dir-locals.el: ("package.json" . ((nil . ((my-var . "value")))))), but something defined in my init.el for all directories.

  • emacs.stackexchange.com/tags/elisp/info
    – Drew
    Commented Mar 29, 2023 at 22:51
  • @Drew my bad, at first I didn't know what tag to use so I put elisp as a placeholder, then searched and added "variables" and forgot to remove the elisp tag placeholder Commented Mar 30, 2023 at 15:03

2 Answers 2


I would use either of:

(add-to-list 'auto-mode-alist '("/package\\.json\\'" . package-json-mode))

(define-derived-mode package-json-mode json-mode "package.json"
  "Major mode for editing package.json files."
  (setq-local VARNAME VALUE))


(add-hook 'json-mode-hook 'my-json-mode-hook)

(defun my-json-mode-hook ()
  "Used in `json-mode-hook'."
  (when (equal (file-name-nondirectory (buffer-file-name)) "package.json")
    (setq-local VARNAME VALUE)))

You could also use find-file-hook instead of json-mode-hook, but I'd prefer the major mode hook to that.

With auto-mode-alist you might (require 'json-mode) first to ensure that its more generic .json pattern doesn't get added after (and hence take precedence over) your package.json pattern; but if you've installed json-mode via the package manager and its autoloads have been loaded ahead of your custom code, you should be safe to ignore that issue.

  • I'm concerned about using new major mode, lets say there's a major mode alist with only json-mode in it, would it be picked up for package-json-mode or not? specifically this github.com/radian-software/apheleia/blob/… Commented Mar 30, 2023 at 15:18
  • 1
    small correction for your second solution, instead of file-name-base it should be file-name-nondirectory gnu.org/software/emacs/manual/html_node/elisp/… Commented Mar 30, 2023 at 15:29
  • As long as the code checking the major mode is well-written it will be using derived-mode-p to test (if there's no specific reason not to do so), in which case anything already targeting json-mode will automatically recognise your derived mode too. (This is one of the intentions behind derived modes.) Situations where they are treated differently are certainly possible, but should be rare.
    – phils
    Commented Mar 30, 2023 at 21:27

Your question isn't too clear to me, as you speak of both "loading" a file and "visiting" a file, which are two different things. I'm assuming you want to set a variable after a file named "package.json" has been loaded.

(with-eval-after-load "package.json"
 (setq my-var  "value")
 ;; .. whatever else you want to do

C-h f with-eval-after-load:

with-eval-after-load is a Lisp macro in subr.el.

(with-eval-after-load FILE &rest BODY)

Execute BODY after FILE is loaded.

FILE is normally a feature name, but it can also be a file name, in case that file does not provide any feature. See eval-after-load for more details about the different forms of FILE and their semantics.

See also the Elisp manual, node Hooks for Loading.

  • 2
    I imagine it's the opposite, and they want to set a buffer-local var when visiting the file. Loading a JSON file wouldn't make sense to me.
    – phils
    Commented Mar 29, 2023 at 23:13
  • @phils: Maybe so. but a library named package.json.el would make sense. That was my assumption. But the question isn't clear...
    – Drew
    Commented Mar 30, 2023 at 3:29
  • sorry for being unclear, I meant visiting a file Commented Mar 30, 2023 at 15:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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