Migrating to Projectile 3.0
Projectile 3.0 is a cleanup and modernization release. There are no big new concepts to learn - the focus was on removing long-deprecated or low-value features and consolidating a few families of near-duplicate commands. Most setups will keep working untouched; this page walks through the changes that can affect an older configuration and how to adapt.
| If you just want the short version, jump to the configuration cheat sheet at the end. |
Requirements
Projectile 3.0 requires Emacs 28.1 or newer (2.x supported 27.1, and older
2.x releases went back further). If you’re on an older Emacs, stay on Projectile
2.x. The bump lets Projectile rely on transient unconditionally, so
projectile-dispatch (s-p m) is now always available rather than an
optional extra.
Removed features
Projectile Commander → the dispatch menu
The single-key "Commander" (projectile-commander and
def-projectile-commander-method) is gone. Its replacement is
projectile-dispatch, a transient menu bound to s-p m. A prefix
argument on project switch (C-u s-p p) also opens it.
If you defined your own commander methods, add them to the dispatch transient
instead (see transient-append-suffix and the projectile-dispatch definition).
The idle timer
projectile-enable-idle-timer, projectile-idle-timer-seconds and
projectile-idle-timer-hook were removed. If you relied on running something
periodically, wire it up yourself:
(run-with-idle-timer 60 t (lambda ()
(when (projectile-project-p)
;; ...
)))
projectile-browse-dirty-projects
Removed. For an overview of repositories with uncommitted changes use
magit-list-repositories or vc-dir, which do this far better than Projectile
ever did.
Built-in tags support
All of the built-in ctags/etags/gtags glue is gone:
projectile-find-tag, projectile-regenerate-tags,
projectile-visit-project-tags-table, and the projectile-tags-command /
projectile-tags-backend options.
Modern code navigation is better served by xref (M-.) backed by a
language server (Eglot/LSP) or etags/ggtags directly, plus
projectile-find-references (s-p s x) for textual references.
projectile-tags-file-name is kept, but only so that a project’s TAGS
file can be excluded from the index. It no longer drives any command.
|
The ido / ivy / helm completion systems
projectile-completion-system used to accept ido, ivy, helm, default,
or auto (which detected ido-mode/ivy-mode/helm-mode). The dedicated
ido/ivy/helm/auto values were removed - it now takes default (Emacs’s
completing-read) or a custom function.
This isn’t a loss of functionality: Vertico, Consult, fido-mode, Ido’s
ido-ubiquitous, and friends all work through completing-read, and
helm-projectile /
counsel-projectile provide
their own dedicated integration. Any of the old values now simply behaves like
default, so nothing breaks - you can just delete the setting.
Legacy keybindings and aliases
The single-letter lifecycle bindings s-p C / s-p K / s-p L /
s-p P / s-p u (configure / package / install / test / run project)
were removed. Use the c prefix instead: s-p c o, s-p c p,
s-p c i, s-p c t, s-p c r.
Two long-obsolete aliases were also deleted: projectile-global-mode (use
projectile-mode) and projectile-project-root-files-functions (use
projectile-project-root-functions).
Consolidated commands
Search
The search commands now share one entry point, projectile-search
(s-p s s), backed by a pluggable backend. projectile-search-backend
picks the backend (auto by default, favouring ripgrep then grep); you can
also register your own with projectile-register-search-backend. See the
Searching section for details.
projectile-grep, projectile-ripgrep and projectile-ag still exist as thin
wrappers that force a specific backend.
One keybinding changed. s-p s s now runs projectile-search
(it used to run projectile-ag), and projectile-ag moved to s-p s a.
s-p s g (grep) and s-p s r (ripgrep) are unchanged.
|
Shells, REPLs and terminals
Similarly, projectile-run (s-p x r) is a single command that opens a
shell/REPL/terminal in the project root using a backend chosen by
projectile-shell-backend (default eshell). The individual commands
(projectile-run-eshell, projectile-run-vterm, …, and their
-other-window variants) are unchanged, and you can add your own terminal with
projectile-register-shell-backend.
Dispatch modifiers instead of "other window / other frame" columns
The projectile-dispatch menu gained modifier switches - -d (--display:
cycle this window / other window / other frame), -r (--regexp),
-n (--new-process) and -i (--invalidate-cache) - which replace
the old dedicated "Other window" and "Other frame" menu columns. The
projectile-command-map 4 <key> / 5 <key> bindings and the
individual -other-window / -other-frame commands are untouched.
Behavior changes
projectile-find-references
projectile-find-references now honours Projectile’s ignore configuration
(.projectile and the globally-ignored files/directories) and searches only the
project’s file set. It previously went through the semantic-symref API, which
scanned the whole tree and ignored that configuration. For semantic (not
textual) references, use the built-in xref-find-references - it is also scoped
to the Projectile project now.
Configuration cheat sheet
| Before (2.x) | After (3.0) |
|---|---|
|
Delete it, or |
|
|
|
Roll your own with |
|
|
|
|
s-p s s (was |
|
s-p C / s-p K / s-p L / s-p P / s-p u |
s-p c o / s-p c p / s-p c i / s-p c t / s-p c r |
|
|
Emacs 27.1+ |
Emacs 28.1+ |