File and directory local settings

Emacs can be configured on a per-file, directory, or mode basis using file or directory local settings. This involves a special comment at the top or bottom of the file, or in a .dir-locals.el file.

File local variables

These can be set in a special comments (sometimes referred to as a “prop” line, or “mode line” in vim parlance) at the top of the file:

;; -*- mode: emacs-lisp; lexical-binding: t; -*-

Or a commented block at the bottom of the file:

;; Local Variables:
;; mode: org-mode
;; indent-tabs-mode: t
;; tab-width: 4
;; eval: (flycheck-mode -1)
;; eval: (add-hook 'after-save-hook #'org-babel-execute-buffer t t)
;; End:

Rather than hand-write these, use these commands instead:

  • M-x add-file-local-variable
  • M-x add-file-local-variable-prop-line and M-x copy-dir-locals-to-file-locals-prop-line

Directory or project local variables

A .dir-locals.el file applies its settings to any Emacs buffer opened within its parent or any sub-directory. Use it to configure Emacs on a per-mode or file basis, or to apply settings to all buffers. For example:

((nil (indent-tabs-mode . t)
      (tab-width . 4))
 (go-mode (eval . (flycheck-mode -1)))
 (org-mode (buffer-read-only . t))
 ("src/" (tab-width . 8))
 ("src/some/file.txt" (fill-column . 100))
  • ((nil (indent-tabs-mode . t)
          (tab-width . 4))
    

    This sets indent-tabs-mode to t and tab-width to 4 in all buffers opened in this directory (or any sub-directory).

  •  (go-mode (eval . (flycheck-mode -1)))
     (org-mode (buffer-read-only . t))
    

    This disables flycheck-mode in any go-mode buffer opened in this or any sub-directory, and sets buffer-read-only to t in any org-mode buffer.

  •  ("src/" (tab-width . 8))
    

    These settings can apply to any file in src/ (recursive).

  •  ("src/some/file.txt" (fill-column . 100))
    

    And this only applies to a single file, regardless of mode.

Rather than hand-write this file, use these commands instead:

  • M-x add-dir-local-variable (targets the .dir-locals.el in the currect directory)
  • M-x projectile-edit-dir-locals (targets the .dir-locals.el in the root of your current project)

Security and local variables

Emacs will prompt you before it sets any variables or evaluates any code you haven’t personally declared as “safe”, but how do you do that? Either:

  • By adding (VAR . VAL) to safe-local-variables-values where VAR is the name of the variable and VAL is a safe value for it to have. e.g.

    (add-to-list 'safe-local-variables-values '(flycheck-disabled-checkers . (emacs-lisp-checkdoc)))
    
  • safe-local-eval-forms is similar; it’s a list of lisp forms that are safe to be evaluated from local variables. e.g.

    (add-to-list 'safe-local-eval-forms '(add-hook 'before-save-hook #'delete-trailing-whitespace nil t))
    
  • Alternatively, you can declare any value for a variable as safe with:

    (put 'SYMBOL 'safe-local-variable t)
    

    Or, at least, any value that satisfies a predicate:

    ;; `SYMBOL' can only be set to a string value.
    (put 'SYMBOL 'safe-local-variable 'stringp)
    

There is another option, but I wouldn’t recommend it:

;; Dangerous! Allows any setting or code to be run, no questions asked!
(setq enable-local-variables :all)

If you only want to suppress the prompts and auto-ignore unsafe variables, use:

(setq enable-local-variables :safe)
2 Likes