This is the second part of my series of articles describing how to make Emacs a great JavaScript development environment. This time we’ll focus on getting good auto-completion with type inference.

If you haven’t read it yet, you should jump to the first post first to get things started.

Setting up Tern & company-mode for auto-completion

Tern is a great tool once setup correctly. It parses JavaScript files in a project and does type inference to provide meaningful completion (with type hints) and support for cross-references.

Unfortunately, cross-references with tern never reliably worked for me, that’s why I have always been using xref-js2 instead for that (see part #1).

For auto-completion, we’ll be using company-mode with tern. Let’s go ahead and install tern:

$ sudo npm install -g tern

Now let’s install the Emacs packages:

M-x package-install RET company-tern RET

The Emacs configuration is straight-forward, we simply enable company-mode with the tern backend for JavaScript buffers:

(require 'company-mode)
(require 'company-tern)

(add-to-list 'company-backends 'company-tern)
(add-hook 'js2-mode-hook (lambda ()
;; Disable completion keybindings, as we use xref-js2 instead
(define-key tern-mode-keymap (kbd "M-.") nil)
(define-key tern-mode-keymap (kbd "M-,") nil)

Now, depending on your JavaScript project, you might want to setup tern to work with your project structure. If completion doesn’t work out of the box using tern defaults you will have to set it up using a .tern-project placed in the root folder containing your JavaScript files.

Here’s an example setup for a project that uses requirejs and jQuery, ignoring files from the bower_components directory:

  "libs": [
  "loadEagerly": [
  "dontLoad": [
  "plugins": {
    "requirejs": {
      "baseURL": "./"

Once setup, tern offers superb completion. Together with company-mode, you get great context-based completion with type inference.


When completing a function, you can hit <F1> to get its documentation:

Ternjs documentation

Until next time

In the next articles I’ll cover linting with Flycheck, gulp and grunt integration into Emacs, and of course how to setup and use Indium.