jinx.el: a just-in-time spell checker for Emacs built on Enchant
🪄 Enchanted Spell Checker
At a glance
- What is it?
- Jinx is an Emacs Lisp spell checker that checks only the visible part of a buffer, lazily, by binding directly to the Enchant library through a compiled native module instead of talking to Ispell as a subprocess. It suits Emacs users who want the built-in spell checker replaced by something faster, and it needs an Emacs with dynamic module support plus libenchant.
- Who is it for?
- Jinx is the right choice for an Emacs user on a slow machine or in a large buffer who wants spelling to stop costing time, since the visible-window-only design and the in-process Enchant binding remove the two costs that make Ispell unpleasant. It is the wrong choice for a stock Emacs build without dynamic module support, for anyone unwilling to install a C compiler and libenchant, and for Windows without manual intervention during the native module build.
- Can I use it commercially?
- Yes, with conditions. GPL-3.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
- Is it still maintained?
- Yes. The repository last received commits 27 days ago.
- What is it written in?
- Mainly Emacs Lisp, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What Jinx checks: only the visible portion of the buffer
Jinx is described as a fast just-in-time spell-checker for Emacs, and the design decision that makes it fast is stated in the first paragraph: it highlights misspelled words in the text of the visible portion of the buffer.
That is a different contract from the built-in spell checker. Emacs's Ispell-based checking works over whole buffers, which means opening a large file or switching buffers costs a spell check of everything in it. Jinx instead highlights lazily and recognises window boundaries and text folding, so when you unfold a region or scroll, only the newly visible part of the text is checked, and only if it has not been checked before.
The second half of the feature is correction. Each misspelling can be corrected from a list of dictionary words presented as a completion menu, which means the correction flow uses the same completion machinery Emacs users already know rather than a separate prompt buffer with its own keys.
The package is positioned as a full replacement for the built-in Ispell spell checker, and the README is clear that it is designed to be used completely on its own. It can, however, safely co-exist with Ispell, which matters during a gradual migration or in setups where other packages still call Ispell functions.
The project is a single Emacs Lisp file, jinx.el, alongside a C source file jinx-mod.c and the emacs-module.h header, which is the whole implementation. The author is Daniel Mendler, and the licence is GPL-3.0.
Why it is fast: a native module instead of a subprocess
The README attributes Jinx's high performance and low resource usage to directly calling the API of the Enchant library, and to binding directly to the native Enchant API avoiding slower inter-process communication.
That is the whole trick, and it is worth understanding what it buys. A spell checker that runs as a separate process pays for every word check with a pipe round trip, a process dispatch and a serialization step. Batching helps, but the round trip is still there, and on a large buffer it is the dominant cost. Calling into Enchant through a compiled module turns each check into a function call across a language boundary that costs far less than a process.
Jinx automatically compiles jinx-mod.c and loads the dynamic module at startup, so the user does not build anything by hand. The compiled module is the part with the C compiler requirement, and it is why the installation section insists on a compiler and on libenchant rather than treating them as optional.
Enchant itself is a layer over other spell checkers. The README notes that Enchant is used by other text editors and supports multiple backends like Nuspell, Hunspell and Aspell, as well as the system spell checkers of Mac or Windows. So the choice of Enchant is not a lock-in to one dictionary implementation: on a Mac or a Windows machine the system checker can serve as the backend, while on Linux you pick a dictionary package.
Jinx is also multi-language, checking multiple languages in the same buffer, with the jinx-languages variable for customisation. For a document that mixes prose in one language with code identifiers in another, that is the feature that makes the tool usable rather than merely fast.
Installing: package archives, a C compiler and libenchant
Jinx can be installed from ELPA or MELPA directly with package-install, which is the ordinary Emacs package path. The requirements are what make it more than a one-liner.
Your Emacs must be compiled with dynamic module support, a C compiler must be available on your system, gcc or clang, and Jinx requires libenchant, which is needed to compile the native module at install time. If pkgconf or pkg-config is available, Jinx uses it to locate libenchant during installation.
The distribution package names differ, and the README lists them per platform: libenchant-2-dev and pkgconf on Debian and Ubuntu, enchant and pkgconf on Arch and Gentoo, emacs-jinx defined in emacs-xyz.scm on Guix, jinx defined in elpa-packages.nix on Nix, enchant2-devel and pkgconf on Void, emacs-jinx or enchant2-devel with pkgconf-pkg-config on Fedora, emacs-jinx or enchant-devel with pkgconf-pkg-config on OpenSUSE, and enchant2 with pkgconf on FreeBSD, OpenBSD and Mac.
One platform note stands out: on Windows the installation of the native module may require manual intervention. That is the cost of the approach, since the module has to be compiled for the platform it will run on.
The package is also distributed through the standard archives, with badges pointing at GNU ELPA, GNU-devel ELPA, MELPA Releases and MELPA Snapshots, so a user who prefers a released package over a snapshot can pick one.
Turning it on: global mode, per-mode mode and the use-package form
Jinx has two modes. The command global-jinx-mode activates globally, and the command jinx-mode is for activating it for specific modes. The README shows both ways of hooking it up:
;; Alternative 1: Enable Jinx globally
(add-hook 'emacs-startup-hook #'global-jinx-mode)
;; Alternative 2: Enable Jinx per mode
(dolist (hook '(text-mode-hook prog-mode-hook conf-mode-hook))
(add-hook hook #'jinx-mode))The commands jinx-correct and jinx-languages are marked as autoloads, so they are available without the package being loaded in advance, which matters for a package that is meant to be enabled from the startup hook.
Key bindings are the second decision. The recommended binding for correction is M-$, which takes over that key from the default assignment to ispell-word. Because Jinx is independent of the Ispell package, M-$ can be re-used, so a configuration that has both Jinx and Ispell does not need to invent a new key. The README pairs it with C-M-$ for jinx-languages:
(keymap-global-set "M-$" #'jinx-correct)
(keymap-global-set "C-M-$" #'jinx-languages)And for anyone who uses the use-package macro, the README gives the equivalent form:
(use-package jinx
:hook (emacs-startup . global-jinx-mode)
:bind (("M-$" . jinx-correct)
("C-M-$" . jinx-languages)))The Jinx Wiki linked from the README carries the detail the main document leaves out, including configurations to save misspellings as global abbreviations and support for the Ispell LocalWords mechanism, which is how a project-specific vocabulary gets shared with an existing Ispell setup.
Correcting words: the completion menu and the four dictionaries
The easiest way to correct a misspelling is to right click the word, which is underlined with a wavy line, and pick from a context menu of suggestions. The keyboard route is the jinx-correct command, and the recommended binding is M-$, with C-u M-$ or M-x jinx-correct-all to spell-check the entire buffer.
Suggested corrections appear as a completion menu, and you can press the displayed digit keys to select a suggestion quickly. The menu also offers to save the word temporarily for the current session, in the personal dictionary, or in the file-local or directory-local variables. Words can be removed from those places again with M-x jinx-remove-word.
Those four destinations are the interesting part of the design. Session scope covers the current session, the personal dictionary covers the user across buffers, and file-local and directory-local variables cover a project or a directory, which is how a team shares vocabulary without a shared dictionary file. The fact that all four are reachable from the same menu means the scope decision is made at the moment of correction, where you know the word.
The prompt accepts arbitrary input, so you can type a correction that is not in the list. A specific convention is documented with the example of a typo such as alotriomorpc: the prompt offers the option @alotriomorpc, and selecting it adds that word to the personal dictionary. You can then correct the option to @allotriomorphic and add it to the dictionary, which is a two-step way to register a word and its corrected spelling in one interaction.
While inside the jinx-correct prompt, M-n and M-p are bound to jinx-next and jinx-previous and move to the next and previous misspelled word, so a whole document can be corrected without leaving the prompt.
Ignoring what should not be flagged, and the limits of the package
A spell checker in a programming editor has to decide what a word is, and Jinx exposes that decision. It can flexibly ignore misspellings via faces, with jinx-exclude-faces and jinx-include-faces, via regular expressions, with jinx-exclude-regexps, and via programmable predicates. It supports spell-checking multiple languages in the same buffer, with jinx-languages for customisation.
For code it has a specific rule. Jinx comes preconfigured for the most important Emacs major modes, and modes like JavaScript, TypeScript, Java, Ruby or Rust are listed in jinx-camel-modes, where composite words in camelCase and PascalCase are accepted. So a JavaScript file with a variable named getUserName is not flagged as three misspellings, and the exclusion list is a variable you can extend.
The limits are mostly about the host. The Emacs build must have dynamic module support, which rules out a stock Emacs compiled without it. A C compiler and libenchant have to be present at install time. Windows needs manual intervention for the native module. And the project has no GitHub releases, with the last push on 2026-09-26, so installation goes through the package archives rather than a tagged version, and NEWS.org in the repository is the changelog.
There is also a design consequence worth stating plainly. The whole performance argument rests on checking only what is visible, so a checker that never sees the folded or off-screen parts of a buffer cannot tell you about a misspelling you have not scrolled to. For a spell checker that is a reasonable trade, and it is why Jinx coexists comfortably with the notion of a background buffer-wide check, but it does mean that finding every misspelling in a long document requires the whole-buffer command.
The alternative approach is the built-in spell checker with a different dictionary and a different backend, which costs the subprocess round trip on every check. The real comparison is with a modern third-party checker that treats code as text anyway, and Jinx's advantage there is that it knows about camelCase modes, faces and buffer-local dictionaries.
Editorial conclusion
Jinx is the right choice for an Emacs user on a slow machine or in a large buffer who wants spelling to stop costing time, since the visible-window-only design and the in-process Enchant binding remove the two costs that make Ispell unpleasant. It is the wrong choice for a stock Emacs build without dynamic module support, for anyone unwilling to install a C compiler and libenchant, and for Windows without manual intervention during the native module build. Verify first that your Emacs was compiled with module support, that libenchant and pkg-config are present before you install the package, and that the key binding you want for M-$ does not collide with an existing command in your configuration.
Frequently asked questions
What do I need to install Jinx?
Your Emacs must be compiled with dynamic module support, a C compiler must be available on your system, gcc or clang, and Jinx requires libenchant to compile the native module at install time. If pkgconf or pkg-config is present, Jinx uses it to locate libenchant. The package itself installs from ELPA or MELPA with package-install.
How do I enable Jinx in my Emacs configuration?
Either add global-jinx-mode to the emacs-startup-hook, or enable jinx-mode on specific mode hooks such as text-mode-hook, prog-mode-hook and conf-mode-hook. A use-package form with :hook (emacs-startup . global-jinx-mode) is also shown in the README.
Can Jinx replace the built-in Ispell spell checker?
Yes. The README says Jinx is designed as a full replacement for Emacs's built-in Ispell spell checker and can be used completely on its own, though it can also safely co-exist with it. Because Jinx is independent of the Ispell package, the M-$ key can be reused for jinx-correct.
How do I correct a misspelling and where can saved words go?
Right click the underlined word and choose a suggestion, or invoke jinx-correct and use the completion menu with the digit keys. The menu can save a word temporarily for the session, in the personal dictionary, or in the file-local or directory-local variables, and M-x jinx-remove-word removes them again.
Does Jinx understand camelCase identifiers?
Yes, for the modes listed in jinx-camel-modes, which the README says includes JavaScript, TypeScript, Java, Ruby and Rust. For those modes composite words in camelCase and PascalCase are accepted rather than flagged.
What are the limitations of Jinx on Windows?
The README states that on Windows the installation of the native module may require manual intervention, since the module is compiled at install time. Beyond that, the package requires an Emacs built with dynamic module support and libenchant present.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/minad-jinx)Was this useful?