JesseHerrick

JesseHerrick

Dexter - A fast, full-featured Elixir LSP optimized for large codebases

Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It supports a slew of LSP features like go-to-definition, go-to-references, hover docs, near instant formatting, renaming of modules, functions, and variables across the codebase, and more.

Remote’s Elixir codebase is enormous (over 57k files) so we have run into every bottleneck you can imagine with the existing LSPs. Expert works great on smaller codebases, but it can’t yet handle codebases of our size. On our codebase, we’re usually not even able to get it to finish indexing.

Dexter started as a CLI tool I wrote for myself to improve my search keybindings for jumping around files due to not having a working LSP. I quickly realized that I had built the foundations for an LSP without the server. So I added an LSP server in front and Dexter was born. I released Dexter internally at Remote last week and the feedback has been very positive, so I wanted to open source it to help others with similar issues and give back to the community.

Dexter takes a different approach than the other Elixir LSPs. Rather than attempting to compile the codebase and glean info from the compiled code and parsed AST, Dexter simply parses the code of your project and dependencies directly. I was surprised by how fast and accurate this approach can be.

Everything in Dexter is built for speed without sacrificing correctness. There are limitations to the pure text-based approach, but we’re able to work around those with clever parsing and deferring any complicated macro/import injection tracing to runtime.

I know that the Elixir community has consolidated around Expert, which I think has been a great move. Dexter takes a different approach to the compilation-based LSPs to solve the specific pains we’ve had at Remote with such a large Elixir codebase, so I imagine it will be very helpful for those working on large codebases (although it works great on small codebases too!). While not everything is applicable, I’d imagine that there are some optimizations that we did in Dexter that could be similarly considered in Expert. But that being said, we’re really enjoying using Dexter at Remote and plan to continue maintaining and improving it into the future.

Give it a try and let me know what you think!

To install (assuming you have SQLite installed, if not install it first):

mise plugin add dexter https://github.com/remoteoss/dexter.git && mise use -g dexter@latest

And then just configure your editor, either with the VS Code/Cursor extension, NeoVim, or your other favorite editor.

If you have any thoughts, feature requests, or bug reports, I’d love to hear them. Likewise, contributions are absolutely welcome to the project.


Features

  • Fast indexing — cold index completes in ~11s on a 57k-file Elixir monorepo, ~100ms on Oban, ~300ms on the Elixir standard library (measured on an M1 MacBook Pro). After your first index, incremental indexing makes sure that you never have to reindex the whole codebase again.
  • Go-to-definition — jump to any module, function, type, or variable definition. Resolves aliases, imports, defdelegate chains, use injections, and the Elixir stdlib. Handles all definition forms: def, defp, defmacro, defprotocol, defimpl, defstruct, and more.
  • Go-to-references — find all usages of a function or module across the codebase, including through import, use chains, and defdelegate.
  • Hover documentation@doc, @moduledoc, @typedoc, and @spec annotations rendered as Markdown when you hover over a symbol.
  • Autocompletion — modules, functions, types, and variables with full snippet support. Resolves through aliases, imports, use injections, and the Elixir stdlib. Works for qualified calls (MyApp.Repo.|), bare function calls, and module prefixes.
  • Rename — rename modules, functions, and variables with automatic file renaming when the convention is followed.
  • No compilation required — the index is built by parsing source files directly, not by compiling your project. Dexter works immediately on any codebase, even ones that don’t compile.
  • Monorepo and umbrella support — a single index at the repository root covers all apps and shared libraries. Go-to-definition, find references, and rename work cross-project out of the box.
  • Format on save — formats .ex, .exs, and .heex files on save via a persistent Elixir process. Near-instant after the first save. Formatter plugins (Styler, Phoenix.LiveView.HTMLFormatter) are loaded from your project’s _build — no install needed. Syntax errors are surfaced as diagnostics.
  • Elixir stdlib indexing — jump to Enum, String, Mix, and other bundled modules by indexing your local Elixir installation sources.
  • Signature help — parameter hints as you type function calls.
  • Workspace symbols — search for any module or function across the entire codebase.
  • Call hierarchy — navigate incoming and outgoing calls.
  • Code actions — add missing aliases with a single action.
  • Document symbols — outline view of all functions and modules in the current file.
  • Document highlight — highlight all occurrences of the symbol under the cursor.
  • Variable support — go-to-definition, rename, and completion for local variables via tree-sitter, with correct scoping across case, with, for, and other block constructs.
  • Git branch switch detection — automatically reindexes when you switch branches.

Checkout the GitHub Repo for more details:

https://github.com/remoteoss/dexter

Most Liked

lpil

lpil

Creator of Gleam

Nice work!

One thing I’ve not noticed anyone mention yet (unless I missed it!) is the security benefits of this approach.

Elixir compilation means that executing arbitrary Elixir code, and that can do anything at all. Previously if we wanted to audit a version of a package before adding it to our project (as we should!) we would have to browse the code without any LSP assistance, as doing so would execute not-yet-trusted code. Now with Dexter we can have a proper and modern development environment while exploring new code. Bravo!

hauleth

hauleth

For anyone interested - Nix derivation:

{
  buildGoModule,
  fetchFromGitHub,
  installShellFiles,
  lib,
  stdenv,
}:
let
  name = "dexter";
  version = "0.5.3";
  src = fetchFromGitHub {
    owner = "remoteoss";
    repo = name;
    tag = "v${version}";
    hash = "sha256-8JjxR7Q+4OgBSIgODxIEU/0mC+bPp9Nz7uCAjfn4HiY=";
  };
in
buildGoModule {
  pname = name;

  inherit version src;

  nativeBuildInputs = [ installShellFiles ];

  proxyVendor = true;

  postInstall = ''
    mv $out/bin/cmd $out/bin/dexter
  ''
  + (lib.optionalString (stdenv.buildPlatform.canExecute stdenv.hostPlatform) ''
    installShellCompletion --cmd dexter \
      --bash <($out/bin/dexter completion bash) \
      --fish <($out/bin/dexter completion fish) \
      --zsh <($out/bin/dexter completion zsh)
  '');

  vendorHash = "sha256-1mJ4HdDCsZl/g8F+L+NrW2ACuiHe2aSheJO/1XfKAb4=";

  meta = {
    description = "Fast implementation of Elixir language server in Go";
    mainProgram = "dexter";
    homepage = "https://github.com/remoteoss/dexter";
    license = lib.licenses.mit;
    platforms = lib.platforms.all;
  };
}
egze

egze

Dexter is so fast! At first I was like: huh, it indexed the project already? It must be broken!

But no, it just works. Try it!

Where Next?

Popular in Announcing Top

wmnnd
Hi there, for my project DBLSQD, I needed a file storage solution that is a bit more flexible than Arc. Because I thought others might f...
New
mischov
import Meeseeks.CSS html = HTTPoison.get!("https://news.ycombinator.com/").body for story &lt;- Meeseeks.all(html, css("tr.athing")) do...
New
dominicletz
Hi, I thought I had posted my library before but seems I hadn’t. The project is still in early stages but it’s growing and so I think it...
New
tfwright
After working on it for a couple of months and using it in production for most of that time, today I’ve released LiveAdmin, a LiveView ba...
New
bryanjos
Hi, I wanted share a small library we at Revelry Labs made for rendering react components from the server side. There are instructions fo...
New
zorbash
I created Kitto a framework for dashboards inspired by Dashing. The distributed characteristics of Elixir and the low memory footprint...
New
Azolo
Hey everyone, I just released WebSockex which is a Elixir WebSocket client. WebSockex strives to work as a OTP special process, be RFC6...
New
scohen
Lexical Lexical is a next-generation language server for the Elixir programming language. Features Context aware code completion As-you...
New
tmbb
I’ve decided to create this topic to discuss optimization possibilities for something like Phoenix LiveView. I’ve created this topic unde...
144 10187 141
New
pkrawat1
Hey guyz We at @aviabird are working on a payment library in elixir/phoenix. We are targeting March 2018 to add 56 Gateways to it. Have...
New

Other popular topics Top

senggen
Erlang/OTP 25 [erts-13.2.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] 15:22:35.803 [error] gen_event {lager_file_backend...
New
skosch
To my knowledge, put_in, Map.update etc. all have the one limitation of not automatically creating intermediate keys when needed (for exa...
New
Nvim
Anybody knows a comprehensive comparison of Django and Phoenix, thanks for the help. Where are they similar? Where do they differ the m...
New
JeremM34
Hello, how can I check the Phoenix version ? Thanks !
New
josevalim
Hi everyone, One of the features added to Elixir early on to help integration with Erlang code was the idea of overridable function defi...
New
vegabook
I’m brand new to Phoenix and I have stripped one of the demo applications to the bone. I just want to get an svg up on the screen. Here i...
New
pmjoe
I have a relationship of love and hate with Elixir. Lots of things are just absolutely right, but there are some things that are kind of ...
New
vrod
I am using the Starship cross-shell prompt – it seems pretty nice, but I get some errors: [WARN] - (starship::utils): Executing command ...
New
nsuchy
Hi. I’ve noticed that Windows Powershell has it’s own IEX command and you cannot access Elixir’s IEX due to the conflict. This isn’t a cr...
New
AstonJ
Seen any cool LiveView demos, sample apps or examples? Please post them here! :003:
New

We're in Beta

About us Mission Statement