Projectile 3.0 is finally out, and it’s a big one - easily the biggest release in years. There’s a nice reason for that: this year Projectile turns 15.1 It all started back in the summer of 2011, simply because I was frustrated that find-file-in-project didn’t work on Windows, and somehow that little anniversary made me want to shake things up and finally tackle a whole pile of changes I’d been putting off for ages. Some new features, some long-overdue spring cleaning, and a few things I’d wanted to remove for the better part of a decade.

What’s dead can’t die

There’s a running joke that Projectile is obsolete now that Emacs ships project.el out of the box. I’ve heard it many times, and I even wrote about it when Projectile turned 10 - it’s obviously hard to compete with a built-in package, as it has a home-field advantage you can never match.

But here’s the thing. If it’s really true that Projectile is dead and everyone has moved on to project.el, then that’s oddly liberating. What’s dead can’t die, right? If there are no users left to upset, I can finally go wild with my wildest ideas and stop worrying about breaking the workflows of Projectile’s (non-existent) users. And that’s more or less the spirit in which I approached 3.0 - I stopped being quite so precious about backwards compatibility and just did what I felt was right for the project.

(Turns out there might still be a user or two out there after all, so do skim the migration notes below. Sorry in advance!)

The highlights

There’s a lot in this release - well over a hundred entries in the changelog - but here are the highlights I’m most excited about:

  • projectile-dispatch (bound to s-p m) is a new transient menu that mirrors the command map, so you no longer have to remember every keybinding. It also exposes command modifiers as switches, so you can toggle a regexp search, start a fresh shell, invalidate the cache, or open a result in another window/frame right from the menu.
  • Projectile can now index a project asynchronously, in a background process, so a cold projectile-find-file no longer freezes Emacs while it walks a huge tree. The building blocks are public, so external tools can drive Projectile’s indexing asynchronously as well.
  • There’s a new (optional) projectile-consult integration built on those async data sources. Its finder streams candidates into the minibuffer as the project gets indexed, instead of blocking until indexing is done, while still honouring your VCS and indexing configuration.
  • The various search commands got folded into a single projectile-search, backed by a small, extensible backend registry. It ships grep, ripgrep and ag backends out of the box, and you can register your own (deadgrep, consult-ripgrep, whatever you fancy) in a few lines.
  • The shell, REPL and terminal commands got the same treatment - one projectile-run with shell, eshell, ielm, term, vterm, eat and ghostel backends, plus a seam to plug in your own.
  • The indexers got a thorough going-over - batched stat calls, single directory listings instead of dozens of file-exists-p probes, smarter caching. It all adds up, and it really shows over TRAMP, where every needless round-trip used to hurt. I think that 15 years later I’ve finally solved Projectile’s infamous performance issues over TRAMP![^2]
  • I finally removed a pile of features that had outlived their usefulness - the single-key Commander (superseded by the dispatch menu), the idle timer, projectile-browse-dirty-projects, and all of the built-in tags support (xref and LSP do this far better nowadays).
  • The minimum supported Emacs is now 28.1. That let me drop a heap of compatibility shims and finally make transient a proper dependency instead of an optional extra.
  • Projectile is a better project.el citizen now - it implements more of the protocol (project name, buffers, ignores), so tools built on top of project.el behave correctly in Projectile-managed projects.
  • I also dropped the legacy ido/ivy/helm completion systems - these days everything rides on the standard completing-read, so Vertico, Consult and friends just work. ido fans are the one group that has to lift a finger: install ido-completing-read+ (the package formerly known as ido-ubiquitous) and turn on ido-ubiquitous-mode, and ido will drive Projectile’s prompts just like before.
  • And there’s a pile of smaller quality-of-life additions - subproject compile/test for multi-module projects (c m c / c m t), a %p placeholder for the project name in command strings, projectile-add-and-switch-project, jumping back to the most recent project, and more.

Upgrading

3.0 is a major release for a reason - there are breaking changes. The minimum Emacs version is now 28.1, several long-deprecated commands and options are gone, and a couple of keybindings moved around. I’ve written a dedicated Migrating to Projectile 3.0 guide that walks through everything and how to adapt your config. Most setups will keep working untouched, but please give it a read before you upgrade.

Fifteen years later

As I said back when Projectile turned 10 - it’s always hard to compete with built-in packages. Still, I’m genuinely proud that 15 years in, Projectile is still here and, hopefully, still relevant to at least some of you. It remains one of my favourite projects and the one I reach for every single day.

Huge thanks to everyone who has contributed code, reported bugs, written extensions, or simply used Projectile over the years - none of this would exist without you. I really hope 3.0 isn’t the end of the innovation for Projectile, and that it’ll keep surprising and delighting its users for years to come.

Keep hacking!

  1. Give or take - I started Emacs Prelude the same year, so it’s always been a little hard to say which of my open-source projects was truly first. In my mind it’s always been Projectile. [^2]: Famous last words… I know…