Projectile versus project.el
| As both projects are moving targets this page might not reflect the differences between them accurately. |
Projectile was created at a time when Emacs didn’t feature built-in project
navigation functionality. Eventually this changed in Emacs 25 with the introduction of project.el and a lot of people have been asking what are the advantages of using
Projectile over the built-in library. This section of the documentation will try to answer this question.
When project.el was originally introduced it’s feature-set was quite spartan, but it has added some new features in every Emacs release and circa 2026 it should cover the needs of most casual users. I’m guessing that Projectile inspired many features in project.el, and Projectile itself was inspired by tools like IntelliJ IDEA.
TLDR;
If the functionality in project.el is good enough for you then you should probably use project.el.
At a glance
As of early 2026. (Projectile 2.10 and project.el in Emacs 31)
|
| Projectile | project.el | |
|---|---|---|
Created in |
2011 |
2014 [1] |
Supported Emacs versions |
28.1+ |
26+ [2] |
Built-in |
no |
yes |
Package Availability |
MELPA, MELPA Stable, NonGNU ELPA |
GNU ELPA |
Indexing Strategies |
3 ( |
1 (similar to Projectile’s alien strategy) |
Native Project Config |
Yes ( |
No (uses |
Project Cache |
Yes (persisted to disk) |
In-memory only |
Backend Protocol |
Project-type alist |
|
Built-in Project Types |
60+ |
n/a |
Number of Configuration Options |
~95 |
~25 |
Number of Commands |
~90 |
~35 |
Minor Mode |
Yes |
No |
Global Keybindings |
Require user setup |
Out-of-the-box ( |
Integration with |
Yes |
Yes |
Feature-set |
Extensive |
Essential |
Extensions |
~20 |
~10 |
Contribution Process |
Light-weight |
Somewhat complicated (standard for Emacs) |
Notable Differences
Minor Mode vs Global Keymap
Projectile makes heavy use of projectile-mode, which provides some additional features (e.g. project status in the modeline).
You can use Projectile without it, but I guess few people do so. Most of Projectile’s functionality will work fine even if the mode is not active.
project.el on the other hand, just adds its own keymap under the global keymap (using the prefix C-x p). You can do the same for Projectile,
of course, if you want to.
Project Indexing Strategies
Projectile has multiple project indexing strategies to cover a wide variety of use cases. project.el has only one, which is more or less the same
as Projectile’s alien strategy. Admittedly, that’s probably the most commonly used strategy.
.projectile
Projectile has its own project marker/configuration file. It’s a remnant of the early days of the project where I wanted to build a tool that didn’t
rely on the third-party applications and its significance today is not that big. (it will be completely ignored unless you’re using native or hybrid indexing)
Backend Protocol
project.el defines a small protocol via cl-defgeneric (project-root, project-files, project-buffers, etc.) and ships two backends: a transient one for ad-hoc directories and a VC-aware one. New backends are added with cl-defmethod.
Projectile detects projects via root markers and expresses per-language behavior through project types (projectile-register-project-type). More opinionated, more out of the box, less polymorphic.
What project.el does that Projectile doesn’t (yet)
A few project.el features have no real equivalent in Projectile:
-
project-find-matching-buffer— jump to the equivalent buffer in another known project, matched by relative path. Handy for forks and parallel-layout microservices. -
project-file-history-behaviorset torelativize— when switching projects, file-name history is rewritten as relative paths, so muscle memory carries across projects. -
project-other-window-command/-other-frame-command/-other-tab-command— prefix commands that redirect the next project command’s output. Projectile takes the brute-force route instead: a-other-windowand-other-framevariant for almost every command. -
project-prompterandproject-read-file-name-function— single-function knobs for the project / file-name prompts. Cleaner extension point thanprojectile-completion-system. -
project-prune-zombie-projects(Emacs 31) — finer-grained pruning triggers for zombie projects. Projectile only has a single boolean (projectile-auto-cleanup-known-projects). -
project-vc-cache-timeoutas an alist of(predicate . timeout)pairs, so e.g. remote and local can have different TTLs. -
project-vc-merge-submodules— explicit Git submodule strategy. Projectile has none. -
Sparse-index support on Emacs 31 with Git ≥ 2.35 (
git ls-files --sparse).
We’re at parity (or close) on a few others:
-
project-customize-dirlocalsvsprojectile-edit-dir-locals(we just open the file). -
project-vc-nameandproject-vc-extra-root-markersare covered byprojectile-project-name(via dir-locals) and the project-type system. -
project-list-excludeis covered byprojectile-ignored-projectsandprojectile-ignored-project-function(the latter even accepts a predicate, e.g.file-remote-p).
Concept and command concordance
Side-by-side mapping of the most common entry points. Useful both when picking between the two and when switching from one to the other. Empty cells mean there’s no direct equivalent (which doesn’t necessarily mean the functionality can’t be had — just that you’d need to wire something up yourself).
Project root and detection
| Concept | Projectile | project.el |
|---|---|---|
Project root of |
|
|
Project name |
|
|
Detection hook |
|
|
Extra project markers |
|
|
Native config file |
|
— |
File and directory navigation
| Concept | Projectile | project.el |
|---|---|---|
Find file in project |
|
|
Find file in known projects |
|
— |
Find directory |
|
|
Open dired in root |
|
|
Toggle test ↔ implementation |
|
— |
Find related file |
|
— |
"Other window/frame" variants |
|
|
Buffer management
| Concept | Projectile | project.el |
|---|---|---|
Switch to project buffer |
|
|
List project buffers |
|
|
Kill project buffers |
|
|
Save project buffers |
|
|
Find equivalent buffer in another project |
— |
|
Search and replace
| Concept | Projectile | project.el |
|---|---|---|
Grep |
|
— |
Ripgrep |
|
— |
Ag |
|
— |
Find regex via xref |
— |
|
Multi-occur |
|
— |
Query-replace |
|
|
Find references |
|
(use |
Build, test, run, VC
| Concept | Projectile | project.el |
|---|---|---|
Compile |
|
|
Recompile |
(re-runs last compile per project) |
|
Test |
|
— |
Run |
|
— |
Configure |
|
— |
Install |
|
— |
Package |
|
— |
VC dir |
|
|
Shell, terminal, REPL
| Concept | Projectile | project.el |
|---|---|---|
Shell command in root |
|
|
Async shell command in root |
|
|
|
|
|
|
|
|
|
|
— |
Vterm |
|
— |
Eat |
|
— |
Ghostel |
|
— |
IELM |
|
— |
GDB |
|
— |
Project switching and known projects
| Concept | Projectile | project.el |
|---|---|---|
Switch project |
|
|
Switch to open project |
|
— |
Forget project |
|
|
Forget current |
|
— |
Forget projects under dir |
|
|
Remember project |
|
|
Discover projects in path |
|
— |
Clean up zombies (manual) |
|
|
Auto-clean zombies |
|
|
Known-projects file |
|
|
Block from being remembered |
|
|
Configuration and extension
| Concept | Projectile | project.el |
|---|---|---|
Custom completion UI |
|
|
Custom file-name reader |
— |
|
Persistent file cache |
|
— |
Ignore patterns |
|
|
Per-project name override |
|
|
Edit dir-locals |
|
|
Backend extension |
|
|
Switch-project hook |
|
— |
Projectile’s Pros
-
Projectile targets Emacs 28.1+
-
Projectile has different project indexing strategies, which offer you a lot of flexibility in different situations
-
Projectile supports a lot of project types out-of-the-box (e.g.
ruby,Rails,cabalanddune), with per-type hooks for compile/test/run/install/package/configure -
Projectile has a lot more features, although one can argue that some of them are rarely needed
-
Projectile’s dispatch menu (
projectile-dispatch, atransientinterface) is pretty cool for driving a project! -
Test/implementation toggling, a related-files framework, persistent on-disk caching, integrations with most Emacs shells out of the box
-
-
It’s easier to contribute to Projectile
-
Projectile is hosted in GitHub
-
It accepts pull requests
-
You don’t need to sign a contributor agreement
-
-
Projectile has more extensive documentation
-
You can compare it with project.el’s documentation and decide for yourself
-
Projectile’s Cons
-
Third-party dependency, developed outside of Emacs. This is both a pro and con depending on one’s perspective, but I know that many people prefer built-in packages, so I’ve put it under "cons".
-
Built-in packages in theory should be maintained better (or at least for longer), as they have the Emacs team behind them.
-
While Projectile has a rich ecosystem of extensions, over a long enough period of time likely
project.elwill take the lead.
-
-
Due to its larger size, one can argue that Projectile is more complex than
project.el-
Admittedly I would have done some things differently if I were starting Projectile today, but I don’t think Projectile’s core complexity is high.
-
-
project.elkeeps gaining features each release, and a few of them have no Projectile equivalent yet (see the section above).