Having to learn two different groups of commands for doing the same thing.
The traditional Emacs workflow is to use project.el or projectile for project-management, and a separate package for session-management, which saves and restores your workspace. While these packages can do much more, many people use them only to save and restore a project as they left it. That split forces you to remember two different groups of commands.
Project-x collapses that split: every project is a session, and restoring a session is identical to restoring a project. That means you keep the same project.el keybindings you’re already familiar with, while Project-x transparently handles saving, restoring, and syncing the project’s session state.
So:
project-switch-projectnow also switches sessionsproject-kill-bufferscloses the project and the session, optionally saving the session state right where you left offproject-forget-projectnow automatically clears session data as well as removing the project
As of v0.3.0,
project-xincludesproject-x-tabs-mode. Which replaces othertab-bar-modepackages like tabspaces or one-tab-per-project, as an all-in-one solution. Using ours provides a few extra benefits such as full context isolation with not justproject.el, but alsoproject-xcommands. However, you can still choose to keep this off and continue using the above solutions(or none).
- Enhanced project switching: When you switch projects you switch window configurations too, (re)opening files as needed.
- Restoring project state in a new Emacs instance. Note the new option (“Restore windows”) dynamically added to the project dispatch menu when a session exists:
You can install project-x from MELPA:
(use-package project-x
:ensure t
:after project
:config
;; auto-save project state after 5 seconds of idle time
(setq project-x-auto-save-delay 5) ; nil to disable autosave
;; use the custom prompter that shows session labels (optional)
(setq project-prompter #'project-x--project-prompt)
(project-x-mode 1)
;; tab-bar-mode integration (optional)
(project-x-tabs-mode 1))If you prefer not to use the opinionated project-x-mode, you can selectively enable its features. Note that enabling project-x-mode handles the dynamic dispatch menu advice for you, so manual configuration requires a bit more wiring:
(use-package project-x
:ensure t
:after project
:config
(add-hook 'project-find-functions #'project-x-try-local 90)
(add-hook 'kill-emacs-hook #'project-x--window-state-write)
(advice-add 'project-switch-project :around #'project-x--dynamic-switch-commands)
:bind (("C-x p w" . project-x-window-state-save)
("C-x p j" . project-x-window-state-load)))There are four main customization options right now:
project-x-window-list-file: File to store project window configurations. Defaults to your emacs user directory.project-x-local-identifier: String matched against file names to decide if a directory (or some parent thereof) is a project. Defaults to.project. You can also supply a list of strings. For example, Node projects usepackage.json, Elixir usesmix.exs, and Julia usesProject.toml. You can identify all of these as project roots by setting:(setq project-x-local-identifier '("package.json" "mix.exs" "Project.toml" ".project"))
project-x-auto-save-delay: Number of seconds of idle time before auto-saving the current project window configuration. Defaults tonil(autosave disabled). This requiresproject-x-modeto be turned on. The save is debounced: Emacs must be idle for this many seconds after a window or buffer change before the state is written.project-x-save-extra-buffers: Boolean to control whether special non-file buffers (magit-status,eshell,compilation) are tracked. Defaults tonil.project-x-layout-persist-active: Boolean controlling whether a projects active layout is remembered across Emacs restarts. Default ist: whichever layout you were last on, stays active next time you switch into that project. Set tonilif you want to always load"default"instead.
The project-x-mode minor-mode is provided for convenience. It defines keys under the project-prefix-map (C-x p):
| Keybinding | Command | Effect |
|---|---|---|
C-x p w | project-x-window-state-save | Save to the project’s active layout |
C-x p j | project-x-window-state-load | Load session from a project |
C-x p J | project-x-windows | Reload session for the current project |
C-x p a | project-x-add-local-project | Add project + root marker |
C-x p r | project-x-rename-session | Rename the session (without changing path) |
C-x p d | project-x-clear-session | Clear session data (all layouts) |
C-x p l s | project-x-window-state-save-as | Save the current layout under a (new) name |
C-x p l l | project-x-switch-layout | Switch the project to a different saved layout |
C-x p l d | project-x-delete-layout | Delete a saved layout |
- To add a new project (+ root marker), do
C-x p awith DIR. To remove it from the project list, useproject-forget-project. - Enter the project with
project-switch-projectorC-x p j, and save the current session state withC-x p w. - If
project-x-auto-save-delayis set, your session is saved automatically once Emacs is idle for the specified number of seconds (e.g. after switching buffers or changing window layout). - If you make any changes (buffers, windows, etc.),
C-x p Jwill revert back to the last saved session state for the current project. - Optionally use
C-x p rto rename the session label. This only changes the display name, the project path is untouched. Ifproject-x-tabs-modeis active, the corresponding tab is renamed automatically. - To close the session, use
project-kill-buffers.
Every project now has one active layout (called "default" until you name it otherwise), and C-x p w / auto-save always targets it.
To keep several layouts for the same project:
- Arrange your windows the way you want, then run
C-x p l s(project-x-window-state-save-as) and give it a name, e.g."debugging". - Repeat for as many layouts as you want (
"writing","review", etc). From then on,C-x p wsaves back to whichever layout is currently active, so you don’t need to keep re-typing the name. - Use
C-x p l l(project-x-switch-layout) to jump between saved layouts for the current project. Whichever one you switch to becomes the new active layout. - Use
C-x p l d(project-x-delete-layout) to remove a layout you no longer need. The last remaining layout for a project can’t be deleted this way, useC-x p dto clear the whole session instead.
By default the layout you left a project on is what’s restored the next time you load it (project-x-layout-persist-active is t). If you’d rather every project always start on the "default" layout, change project-x-layout-persist-active to nil.
To recognize ‘local’ projects with a root marker somewhere in the path, turn on project-x-mode OR run:
(add-hook 'project-find-functions #'project-x-try-local 90)All project.el features should work as expected (Now works with project-vc-extra-root-markers in Emacs 29+).
- This is currently limited to storing only the current frame configuration.
- The only state saved is your project files,
diredbuffers, and (if enabled viaproject-x-save-extra-buffers)magit-status,eshell, andcompilationbuffers. No minor modes, registers, or other special buffers are recorded. For complete recall, look into the built-in Desktop library. - If you use multiple Emacs instances, project states saved to disk can get overwritten.
Project-x uses window configurations under the hood. However, it has a few advantages:
- Your project state remains persistent across sessions, and any files or dired buffers are reopened if necessary.
- Your project state is associated with the project instead of with registers or data structures from other packages.
If you think in terms of projects, you may find it more convenient to use project-x through the project dispatch menu (C-x p p) to continue working from where you left off. This is a helper library to define and handle projects, not an overarching modification to your Emacs usage pattern. If you want full tab isolation, project-x-tabs-mode is now built in.
project-x-tabs-mode is heavily inspired by and borrows from otpp.el. The key improvement with using it inside project-x instead is that your renamed session labels and tab names are synced, renaming one renames the other. In addition, restoring a session with project-x-windows will now always use the tab’s root project, rather than the buffers. However, if you still want a standalone tab package decoupled from project-x with more features, otpp.el remains an excellent option.
Burly provides a more universal method to save and restore frames and window configurations as Emacs bookmarks (thus persistent across sessions) that is not limited to the project metaphor. If you are looking for this feature but in a more general Emacs context you might be better served by it.
See Limitations. Desktop restores your entire session, this is a much diminished version of the same for individual projects. But desktop being an all-or-nothing affair (without extensive customization) is also a disadvantage. Here each project gets its own desktop state.
project.el is built-in and fast, and project-x is only a small addition to it. As far as I know, Projectile does not natively offer the ability to save and restore your project sessions (including window configurations) out of the box.
As of 2026, this package is maintained by @vmargb. Original author: Karthik Chikmagalur.
Contributions are welcome! Please:
- Open an issue to discuss the change you’d like to make
- Fork the repository and create a feature branch
- Submit a pull request with a clear description of your changes
project-x creates entries containing project state information for a project in the data structure it uses (an associative list) only when you save its state. Thus it should remain fast even if you have thousands of projects so long as you actively work on a few at a time. If you experience slowdown, please raise an issue.
- New in v0.3.1: Multiple named window layouts per project (
project-x-window-state-save-as,project-x-switch-layout,project-x-delete-layout, bound underC-x p l), andproject-x-layout-persist-activeto control whether the active layout is remembered across restarts or always resets to"default". - New in v0.3.0:
project-x-tabs-mode. Handles built-intab-bar-modeactions during project switching, as well as context isolation for allproject.elcommands. Renaming a session viaC-x p rnow also renames the corresponding tab. - New in v0.2.4: Added the custom toggle option
project-x-save-extra-buffersto let users opt-out of saving or restoring special buffers (magit,eshell,compilation). Also added general optimisations for window restoration. - New in v0.2.3: Replaced fixed-interval autosave with a debounced idle-timer (
project-x-auto-save-delay). Added support for saving and restoringmagit-status,eshell, andcompilationbuffers alongside regular file anddiredbuffers.project-forget-projectnow automatically removes session data. - New in v0.2.2: Fixed major bug where Emacs’s
uniquifypreventsproject-switch-projectfrom correctly restoring sessions. Fixed identical directory and buffer name causing race conditions. - New in v0.2.1:
project-prompterfor cleaner format &project-x-rename-sessionto rename a session. - New in v0.2.0:
project-x-add-local-project& more reliable use ofproject-switch-project(+ Emacs 30 support) - New in v0.1.6:
project-x-local-identifiercan now be a list of file names - New in v0.1.5: Autosave the state of the active project periodically.

