Helix is a modal text editor for the terminal, written in Rust. Its editing model is heavily inspired by Kakoune and Neovim: you select first, then act. Helix ships with multiple-selection editing, built-in Language Server Protocol (LSP) support, smart incremental syntax highlighting via tree-sitter, and a debugger client — all configured through plain TOML files, with no plugins or external dependencies required to get started.
This guide takes you from installation through everyday editing, multi-cursor workflows, language-server features, configuration, and a complete keybinding and command reference.
Note
The Helix binary is named
hx. A few package managers (notably Arch'sextrarepository) install it ashelixinstead. Ifhxis not found after installation, tryhelix.
Table of Contents
- Quick Start
- Installation
- Core Concepts
- Everyday Editing
- Multiple Selections
- Search and Replace
- Textobjects and Surround
- Working with Files, Buffers, and Splits
- Pickers and Fuzzy Finding
- Language Server Features
- The Command Line
- Shell Integration
- Registers and Macros
- Configuration
- Key Remapping
- Themes
- Configuring Languages and Language Servers
- Workspace Trust
- Migrating from Vim
- Troubleshooting
- Frequently Asked Questions
- Reference
1. Quick Start
If you just want to start editing immediately, here is the shortest path.
Tip
Helix ships with an interactive tutorial. Run
hx --tutor(or:tutorfrom inside the editor) for a hands-on introduction. It is the single best way to learn the editing model, and most new users finish it in well under an hour.
Install, then open a file
macOS
brew install helix
hx myfile.txt
Linux (Fedora/RHEL)
sudo dnf install helix
hx myfile.txt
Windows
winget install Helix.Helix
hx myfile.txt
The five things to know first
| You want to… | Do this |
|---|---|
| Type text | Press i to enter insert mode, then type. Esc returns to normal mode. |
| Move around | In normal mode, use h j k l (or arrow keys) and w/b for words. |
| Save | Type :w then Enter. |
| Quit | Type :q then Enter (:wq to save and quit). |
| Open another file | Press Space then f to open the file picker. |
Important
Helix is modal. When you launch it you are in normal mode, where letter keys run commands instead of inserting text. To type literal characters you must first enter insert mode with
i,a,o, or similar. If keys seem to "do strange things," you are almost certainly in normal mode — pressEscand tryi.
Verify your setup
hx --health
Config file: default
Language file: default
Log file: ~/.cache/helix/helix.log
Runtime directories: ~/.config/helix/runtime
...
The health check reports where Helix looks for runtime files, your config, and which language servers and grammars are available. Run it any time something is not working as expected.
2. Installation
The recommended way to install Helix is through your operating system's package manager. For the latest nightly features you can build from source.
Note
To take full advantage of Helix you should also install the language servers for the languages you use (for example
rust-analyzerfor Rust,goplsfor Go,typescript-language-serverfor TypeScript). See Configuring Languages and Language Servers and the Language Server Configurations wiki.
Package managers
Linux
| Distribution | Command | Notes |
|---|---|---|
| Debian 13+ | sudo apt install hx |
Older systems: follow Ubuntu/Mint below. |
| Ubuntu / Mint | Install the .deb from the releases page |
|
| Fedora / RHEL | sudo dnf install helix |
|
| Arch (extra) | sudo pacman -S helix |
Run as helix, not hx. helix-git (AUR) builds master. |
| NixOS | helix attribute in nixpkgs, or the project flake |
nix develop for a dev shell. |
| Flatpak | flatpak install flathub com.helix_editor.Helix |
Run: flatpak run com.helix_editor.Helix. |
| Snap | snap install --classic helix |
Installs as both helix and hx. Ensure /snap/bin is in PATH. |
| Homebrew (Linux) | brew install helix |
macOS
| Method | Command | Notes |
|---|---|---|
| Homebrew | brew install helix |
Latest release. |
| Homebrew HEAD | brew install --HEAD helix |
Latest nightly. |
| MacPorts | sudo port install helix |
Windows
| Method | Command |
|---|---|
| Winget | winget install Helix.Helix |
| Scoop | scoop install helix |
| Chocolatey | choco install helix |
| Packably | packl install helix |
| MSYS2 | pacman -S mingw-w64-ucrt-x86_64-helix |
Pre-built binaries
Download a tarball from the GitHub Releases page.
It contains an hx binary and a runtime directory.
- Add
hxto your$PATH. - Copy the
runtimedirectory to a location Helix searches — a typical Linux/macOS location is~/.config/helix/runtime.
# Example for a Linux/macOS tarball
mkdir -p ~/.config/helix
cp -r runtime ~/.config/helix/runtime
Tip
Run
hx --healthto see exactly which runtime directories Helix searches. You can override the default location by setting theHELIX_RUNTIMEenvironment variable.
The Linux AppImage is another self-contained option:
chmod +x helix-*.AppImage
mkdir -p "$HOME/.local/bin"
mv helix-*.AppImage "$HOME/.local/bin/hx" # ensure ~/.local/bin is in PATH
Building from source
Requirements:
- The Rust toolchain
- Git
- A C++14-compatible compiler (GCC or Clang) to build the tree-sitter grammars
git clone https://github.com/helix-editor/helix
cd helix
cargo install --path helix-term --locked
For an optimized build tuned to your CPU:
cargo install \
--profile opt \
--config 'build.rustflags=["-C", "target-cpu=native"]' \
--path helix-term \
--locked
Either command creates the hx executable and compiles the tree-sitter grammars into the
local runtime folder.
Important
When building from source you must point Helix at its runtime files. On Linux/macOS, either export
HELIX_RUNTIMEor create a symlink:export HELIX_RUNTIME=~/src/helix/runtime # add to ~/.bashrc # or ln -Tsf $PWD/runtime ~/.config/helix/runtimeOn Windows, set
HELIX_RUNTIMEviasetx HELIX_RUNTIME "%userprofile%\src\helix\runtime"or create a directory junction in%appdata%\helix\.
Note
If you use the
musl-libcstandard library, setRUSTFLAGS="-C target-feature=-crt-static"during the build so tree-sitter grammars load correctly. To skip grammar building entirely, setHELIX_DISABLE_AUTO_GRAMMAR_BUILD. You can fetch and build grammars later withhx --grammar fetchandhx --grammar build.
After building, validate the installation with hx --health.
3. Core Concepts
Helix's power comes from a small set of consistent ideas. Understanding them up front makes everything else feel natural.
Modes
Helix is a modal editor — different modes interpret your keystrokes differently.
| Mode | Enter with | Purpose |
|---|---|---|
| Normal | Esc (default) |
Navigation and editing commands. The default mode. |
| Insert | i (and friends) |
Type text directly into the document. |
| Select / extend | v |
Extend selections as you move, then act on them. |
In addition, several minor modes are entered from normal mode for grouped commands:
view (z), goto (g), match (m),
window (Ctrl-w), and space (Space).
Selection-first editing
Inspired by Kakoune, Helix follows the selection → action model: you select what you
want to act on (a word, a line, a paragraph) and then apply the action (delete, change,
yank). This is the reverse of Vim's verb-then-object grammar.
A cursor is just a single-width selection. Whenever you move, you are really moving a selection — which is why every movement immediately shows you exactly what an action will affect.
Multiple selections
Multiple selections are a first-class, everyday tool — not an advanced feature. Instead of "find and replace all," the idiomatic Helix approach is to select every instance at once (one selection per match) and then edit them all simultaneously. See Multiple Selections.
Motions
Motions move the cursor or modify selections — w to the next word, f to find a
character, gg to the top of the file. Because Helix is selection-first, motions in normal
mode replace the selection, while the same motions in select mode extend it.
4. Everyday Editing
This section covers the bread-and-butter keys you will use constantly. The Reference contains the exhaustive tables; what follows is the working set.
Moving around
| Key | Moves to |
|---|---|
h j k l |
Left, down, up, right (arrow keys also work) |
w / b / e |
Next word start / previous word start / next word end |
W / B / E |
Same, but for WHITESPACE-delimited "WORDs" |
f<char> / t<char> |
Find / find-till the next <char> (not confined to the current line) |
F<char> / T<char> |
Find / find-till the previous <char> |
Alt-. |
Repeat the last f/t/m/[/] motion |
Home / End |
Start / end of line |
<n>G or <n>gg |
Go to line number <n> |
Ctrl-d / Ctrl-u |
Half page down / up (moves cursor too) |
Ctrl-f / Ctrl-b |
Full page down / up |
Note
Unlike Vim,
f,F,t, andTare not confined to the current line — they search across line boundaries.
Entering insert mode
| Key | Inserts… |
|---|---|
i |
Before the selection |
a |
After the selection (append) |
I |
At the first non-blank of the line |
A |
At the end of the line |
o |
On a new line below |
O |
On a new line above |
Press Esc to return to normal mode. Changes are grouped into a single undo step per
insert-mode session.
Making changes
| Key | Action |
|---|---|
d |
Delete selection (yanks it to the default register) |
c |
Change selection (delete and enter insert mode) |
Alt-d / Alt-c |
Delete / change without yanking |
r<char> |
Replace each selected character with <char> |
R |
Replace selection with yanked text |
~ |
Toggle case; ` to lowercase, Alt-` to uppercase |
y / p / P |
Yank / paste after / paste before |
> / < |
Indent / unindent |
= |
Format selection (requires an LSP) |
u / U |
Undo / redo |
Alt-u / Alt-U |
Move backward / forward through edit history |
. |
Repeat the last insert |
J |
Join lines inside the selection |
Ctrl-c |
Toggle comments on the selected lines |
Ctrl-a / Ctrl-x |
Increment / decrement the number under the cursor |
Tip
The "delete a word" muscle memory from Vim (
dw) becomeswdin Helix: select the word first (w), then delete (d). Likewisecw→wc(orec). See Migrating from Vim for a full mapping.
A first editing example
To change the word foo under your cursor to bar:
w(ore) to select the word.cto change it — Helix deletesfooand enters insert mode.- Type
bar. Escto return to normal mode.
5. Multiple Selections
Multiple selections are the defining Helix workflow. Master them and large edits become trivial.
Creating selections
| Key | Effect |
|---|---|
s |
Select all regex matches inside the current selection(s) |
S |
Split the selection into sub-selections on regex matches |
Alt-s |
Split selection on newlines (one selection per line) |
C / Alt-C |
Copy a cursor to the next / previous line (add cursor below/above) |
% |
Select the entire file |
x |
Select the current line; press again to extend to the next line |
K / Alt-K |
Keep / remove selections matching a regex |
, |
Collapse to just the primary selection |
Alt-, |
Remove the primary selection |
( / ) |
Rotate which selection is primary (backward / forward) |
Alt-( / Alt-) |
Rotate the contents of the selections |
& |
Align selections into columns |
_ |
Trim whitespace from selections |
The canonical "select all, edit all" workflow
To rename every occurrence of count to total across a file:
%— select the whole file.s— open a regex prompt for selecting matches.- Type
countand pressEnter— now every match is its own selection. c— change all selections at once; typetotal.Esc, then,to collapse back to a single cursor.
Tip
Use
sto narrow within a selection andSto split a selection. Combine withAlt-sto put a cursor on every line, thenAto append at the end of every line simultaneously — a fast way to add a trailing character (like;or,) to many lines.
Note
The status line shows the primary selection index out of the total number of active selections (for example
2/14), so you always know how many cursors are live.
6. Search and Replace
Helix has no dedicated :substitute command — search-and-replace is expressed through
multiple selections.
Searching
| Key | Action |
|---|---|
/ |
Search forward for a regex pattern |
? |
Search backward |
n / N |
Select the next / previous match |
* |
Use the current selection as the search pattern, auto-wrapping word boundaries with \b |
Alt-* |
Use the current selection as the search pattern verbatim |
Search operates on the / register by default. The search prompt accepts full regular
expressions. With editor.search.smart-case enabled (the default), a lowercase pattern is
case-insensitive while a pattern containing an uppercase letter is case-sensitive.
Replacing across a selection
To replace foo with bar inside the current selection:
sfoo<ret>cbar<esc>,
sopens a regex prompt and selects every match inside the selection.foo<ret>finalizes the matches (a cursor on each).cchanges them; typebar.<esc>returns to normal mode;,keeps only the primary selection.
To do this for the whole file, prefix with % to select everything first:
%sfoo<ret>cbar<esc>,
Workspace-wide search
Press Space then / to run a global search across the workspace folder. Results open
in a fuzzy picker. After you jump to a result, press Space then ' to reopen the same
results list.
Tip
The global search picker uses regex (not fuzzy matching). Press
Enterwithout typing a filter to reuse the contents of the search register — for example*Space-/Entersearches for the word currently under the cursor.
7. Textobjects and Surround
Textobjects
Textobjects let you select structured pieces of text — a word, a paragraph, or, with tree-sitter, a function or class.
mi<object>— select inside the objectma<object>— select around the object
Key after mi/ma |
Selects |
|---|---|
w / W |
Word / WORD |
p |
Paragraph |
(, [, ', … |
The specified surround pair |
m |
The closest surround pair |
f |
Function |
t |
Type / class |
a |
Argument / parameter |
c |
Comment |
T |
Test |
x |
(X)HTML element |
Note
The structural textobjects (
f,t,a,c,T,x) require an active tree-sitter grammar and a textobject query file for the language. Coverage varies by language — see the language support matrix.
You can also navigate by textobject using the unimpaired bindings: ]f/[f
for next/previous function, ]t/[t for next/previous type, and so on.
Surround
Helix has built-in surround support similar to vim-surround:
| Key sequence | Action |
|---|---|
ms<char> (after selecting) |
Add surround characters to the selection |
mr<from><to> |
Replace the closest surround pair |
md<char> |
Delete the closest surround pair |
Surround works with multiple selections too. To change every (use) to [use]:
%to select the whole file.s, typeuse,Enterto put a selection on each match.mr([to replace the parentheses with square brackets.
8. Working with Files, Buffers, and Splits
Buffers
Buffers are in-memory representations of open files. You can have many open at once.
| Action | Key / Command |
|---|---|
| Open a file | :open <path> (:o, :e) or Space f |
| Next / previous buffer | gn / gp, or :buffer-next / :buffer-previous |
| Switch buffers (picker) | Space b |
| New scratch buffer | :new |
| Close current buffer | :buffer-close (:bc) |
| Last accessed file | ga |
Saving and quitting
| Command | Aliases | Action |
|---|---|---|
:write |
:w |
Save to disk (optional path argument) |
:write! |
:w! |
Save, creating directories as needed |
:update |
:u |
Save only if the buffer was modified |
:write-all |
:wa |
Save all buffers |
:quit |
:q |
Close the current view |
:quit! |
:q! |
Close, discarding unsaved changes |
:write-quit |
:wq, :x |
Save and close |
:write-quit-all |
:wqa, :xa |
Save all and close all views |
:reload |
:rl |
Discard changes and reload from disk |
Splits (windows)
Press Ctrl-w to enter window mode, then:
| Key | Action |
|---|---|
v |
Vertical split (right) |
s |
Horizontal split (below) |
h/j/k/l |
Move focus between splits |
H/J/K/L |
Swap splits in a direction |
q |
Close the current split |
o |
Close all other splits |
You can also open files directly into a split from the command line: :vsplit <path>
(:vs) or :hsplit <path> (:hs, :sp). Launch Helix with --vsplit or --hsplit to
open multiple files side by side from the shell.
9. Pickers and Fuzzy Finding
Pickers are interactive selection windows. Most are reached from space mode.
| Picker | Key |
|---|---|
| File picker (workspace root) | Space f |
| File picker (working directory) | Space F |
| Buffer picker | Space b |
| Global search | Space / |
| Document symbols (LSP/TS) | Space s |
| Workspace symbols (LSP/TS) | Space S |
| Diagnostics (document) | Space d |
| Diagnostics (workspace) | Space D |
| Jumplist | Space j |
| Changed files (VCS) | Space g |
| Command palette | Space ? |
| Reopen last picker | Space ' |
Navigating and filtering
Within a picker, Tab/Shift-Tab (or arrow keys, or Ctrl-n/Ctrl-p) move between
entries, Enter opens the selection, and Ctrl-s / Ctrl-v open it in a horizontal /
vertical split. Ctrl-t toggles a preview. Esc closes the picker.
Most pickers use fzf-style fuzzy matching.
When a picker has multiple columns you can target one column by prefixing its name with %
(abbreviated to any prefix). For example, in the global search picker:
helix %p .toml !lang
searches for "helix" within files whose path ends in .toml but does not contain
"lang".
Tip
Insert register contents into a picker query with
Ctrl-rfollowed by a register name — for exampleCtrl-r.inserts the current selection, andCtrl-r%inserts the current file path.
10. Language Server Features
Helix has built-in LSP support. Install the language server for your language (see the
wiki), make
sure it is on your $PATH, and Helix uses it automatically for matching files.
| Feature | Key | Command |
|---|---|---|
| Hover documentation | Space k |
hover |
| Go to definition | gd |
goto_definition |
| Go to type definition | gy |
goto_type_definition |
| Go to references | gr |
goto_reference |
| Go to implementation | gi |
goto_implementation |
| Rename symbol | Space r |
rename_symbol |
| Code action | Space a |
code_action |
| Document symbols | Space s |
lsp_or_syntax_symbol_picker |
| Workspace symbols | Space S |
lsp_or_syntax_workspace_symbol_picker |
| Format selection | = |
format_selections |
| Autocomplete (manual trigger) | Ctrl-x (insert mode) |
completion |
| Next / previous diagnostic | ]d / [d |
goto_next_diag / goto_prev_diag |
Note
Mappings marked (LSP) in the keymap reference require an active language server, and those marked (TS) require a tree-sitter grammar for the file type.
Completion pops up automatically as you type (configurable). In the completion menu, Tab /
Shift-Tab cycle entries, Enter accepts, and Ctrl-c rejects.
Useful LSP commands from the command line:
| Command | Action |
|---|---|
:lsp-restart |
Restart the language server(s) for the current file |
:lsp-stop |
Stop the language server(s) for the current file |
:lsp-workspace-command |
Open the workspace command picker |
Debugging (DAP)
Helix includes a Debug Adapter Protocol client. Debug commands live under Space G
(experimental): Space Gl launches a debug target, Space Gb toggles a breakpoint,
Space Gc continues, Space Gi/Space Go/Space Gn step in/out/over. You can also start a
session from the command line with :debug-start (:dbg).
11. The Command Line
Press : to open the command line and run a typable command
like :write or :open. The command line supports quoting, flags, and expansions.
Quoting
Arguments are split on spaces and tabs. Wrap an argument containing spaces in single quotes or backticks to keep it together:
:open 'a b.txt'
Double quotes behave the same but additionally expand their contents (see below). On
Unix you can also escape a space with a backslash: :open a\ b.txt.
Flags
Flags modify command behavior, for example :sort --reverse (or -r). Type - to see
completions for the current command's flags. Use -- to mark the end of flags so following
arguments are treated literally: :open -- -a.txt.
Expansions
Anything beginning with % is an expansion — Helix replaces it before running the
command. The general form is %[<kind>]<open><contents><close>, where the delimiters can be
(), [], {}, <>, or the single characters ', ", |.
With no <kind>, the expansion is a variable:
| Variable | Expands to |
|---|---|
%{cursor_line} |
Primary cursor line number (1-based) |
%{cursor_column} |
Primary cursor column (grapheme clusters, 1-based) |
%{buffer_name} |
Relative path of the current document |
%{file_path_absolute} |
Absolute path of the current document |
%{selection} |
Contents of the primary selection |
%{selection_line_start} / %{selection_line_end} |
Primary selection start / end line |
%{current_working_directory} |
Current working directory |
%{workspace_directory} |
Nearest ancestor containing .git, .svn, .jj, or .helix |
%{language} |
Language name of the current document |
%{line_ending} |
The document's line-ending string |
Other expansion kinds:
- Shell —
%sh{...}runs the contents through your shell and inserts the output. Example::echo %sh{date}. - Unicode —
%u{...}inserts a codepoint. Example::echo %u{25CF}prints●. - Register —
%reg{a}inserts the contents of registera.
:echo %sh{git blame -L %{cursor_line},+1 %{buffer_name}}
Caution
Expansions are only evaluated when you press
Enter. To use a literal%in a shell command, double it::echo %sh{date -u +'%%Y-%%m-%%d'}.
Note
A few commands pass their argument straight to the shell and do not interpret quotes (though expansions still apply):
:insert-output,:append-output,:pipe,:pipe-to, and:run-shell-command.
12. Shell Integration
Helix can pipe selections through external commands directly from normal mode.
| Key | Action |
|---|---|
| |
Pipe each selection through a command, replacing it with the output |
Alt-| |
Pipe each selection into a command, ignoring output |
! |
Run a command, inserting its output before each selection |
Alt-! |
Run a command, appending its output after each selection |
$ |
Pipe each selection into a command; keep selections where it returned 0 |
For example, to sort and de-duplicate selected lines, pipe them through sort -u with |.
To filter selections to only those that match a pattern, use $ with grep -q pattern.
The equivalent command-line forms are :pipe, :pipe-to, :insert-output,
:append-output, and :run-shell-command (:sh, :!).
Tip
The shell used for these commands is the
editor.shellsetting —["sh", "-c"]on Unix and["cmd", "/C"]on Windows by default. Override it in your config if you prefer a different shell.
13. Registers and Macros
Registers
Registers store text and other data, much like a multi-slot clipboard. Select a register
with " before an action — "ay yanks to register a, "op pastes from register o.
Default registers used when none is specified:
| Register | Contains |
|---|---|
/ |
Last search |
: |
Last executed command |
" |
Last yanked text |
@ |
Last recorded macro |
Special registers:
| Register | When read | When written |
|---|---|---|
_ |
Returns nothing | Discards everything (a "black hole") |
# |
Selection indices (1, 2, …) |
Not writable |
. |
Contents of the current selections | Not writable |
% |
Name of the current file | Not writable |
+ |
System clipboard | Yanks to the system clipboard |
* |
Primary (X11/Wayland) clipboard | Yanks to the primary clipboard |
Tip
Use the system clipboard directly via space mode:
Space yyanks to the clipboard,Space p/Space Ppaste from it, andSpace Rreplaces selections with its contents.
Macros
| Key | Action |
|---|---|
Q |
Start / stop recording a macro to a register |
q |
Replay a recorded macro from the selected register |
Macros are experimental. To record into register a: "aQ, perform your edits, then Q
again to stop. Replay with "aq.
14. Configuration
Helix is configured with a config.toml file in your config directory:
- Linux / macOS:
~/.config/helix/config.toml - Windows:
%AppData%\helix\config.toml
Tip
Open your config instantly with
:config-open. After editing, apply changes with:config-reload(no restart needed). On Unix you can also reload by sendingUSR1:pkill -USR1 hx.
A typical starter config:
theme = "onedark"
[editor]
line-number = "relative"
mouse = false
cursorline = true
color-modes = true
bufferline = "multiple"
[editor.cursor-shape]
insert = "bar"
normal = "block"
select = "underline"
[editor.file-picker]
hidden = false
[editor.indent-guides]
render = true
Common everyday settings
| Setting | What it does | Default |
|---|---|---|
theme |
Color theme name (top-level key, not under [editor]) |
— |
editor.line-number |
absolute or relative line numbers |
"absolute" |
editor.mouse |
Enable mouse support | true |
editor.cursorline |
Highlight the line(s) the cursor is on | false |
editor.scrolloff |
Lines of padding kept around the cursor when scrolling | 5 |
editor.bufferline |
Show a buffer bar: never, always, or multiple |
"never" |
editor.color-modes |
Color the mode indicator differently per mode | false |
editor.true-color |
Force truecolor if your terminal isn't auto-detected | false |
editor.auto-format |
Format on save (also needs auto-format in languages.toml) |
true |
editor.auto-save.after-delay.enable |
Auto-save after a delay | false |
editor.cursor-shape.{normal,insert,select} |
Cursor shape per mode (block, bar, underline, hidden) |
"block" |
Note
The complete, every-key configuration reference — all
[editor.*]subsections, statusline elements, gutters, soft-wrap, inline diagnostics, and more — lives in the Helix Admin Guide. This section covers the settings most users reach for first.
Project-local configuration
Place a config.toml and/or languages.toml inside a .helix/ directory at the root of a
project. Those settings are merged on top of your global config and the built-in defaults,
so you can tune behavior per repository.
my-project/
└── .helix/
├── config.toml
└── languages.toml
Important
Loading project-local config and starting language servers can execute code defined by the repository. By default Helix protects you with Workspace Trust — you will be prompted before these features run in a new workspace.
You can also run Helix with a one-off config file: hx -c path/to/custom-config.toml.
15. Key Remapping
Helix supports one-way key remapping through config.toml. There are three kinds of things
you can bind a key to:
- Static commands — built-in commands like
move_char_left(see the static command reference). - Typable commands — anything you can run from
:, like:write. - Macros — a sequence of keys, written as a string starting with
@.
[keys.normal]
C-s = ":w" # Ctrl-s to save
C-o = ":open ~/.config/helix/config.toml" # open your config
a = "move_char_left" # rebind a single key
"C-S-esc" = "extend_line" # Ctrl-Shift-Escape
g = { a = "code_action" } # 'ga' shows code actions
"ret" = ["open_below", "normal_mode"] # run multiple commands in order
"A-x" = "@x<A-d>" # a macro: select line, delete without yank
[keys.insert]
j = { k = "normal_mode" } # 'jk' exits insert mode
Modifiers and special keys
Modifiers use the prefixes C- (Ctrl), S- (Shift), and A- (Alt); combine with a dash,
e.g. C-S-esc. The Super/Windows/Command key is Meta-, Cmd-, or Win- (requires a
terminal supporting the enhanced keyboard protocol).
Special key names include space, ret (Enter), esc, tab, backspace, del, ins,
home, end, pageup, pagedown, left/right/up/down, and lt/gt for </>.
Disable a key by binding it to no_op.
Note
Within a macro string, wrap modifier keys in angle brackets —
<A-x>,<C-x>— to distinguish them from the literal lettersAorC. Also,-cannot follow a modifier; writeAlt+-asA-minus.
Defining your own minor modes
You can nest bindings to create custom minor modes:
# A new minor mode bound to '+'
[keys.normal."+"]
m = ":run-shell-command make"
c = ":run-shell-command cargo build"
t = ":run-shell-command cargo test"
16. Themes
Set a theme at the top of config.toml, or switch at runtime with :theme <name>:
theme = "catppuccin_mocha"
You can configure separate light and dark themes; on terminals that report a light/dark preference, Helix switches automatically:
[theme]
dark = "catppuccin_frappe"
light = "catppuccin_latte"
# fallback = "catppuccin_frappe" # used if the terminal expresses no preference
Creating your own theme
Create ~/.config/helix/themes/mytheme.toml (or %AppData%\helix\themes\ on Windows) and
reference it as theme = "mytheme". Each line styles one scope:
"ui.background" = { bg = "#1e1e2e" }
"keyword" = { fg = "mauve", modifiers = ["bold"] }
"ui.text" = "#cdd6f4"
[palette]
mauve = "#cba6f7"
Colors are CSS hex strings (#RGB or #RRGGBB) or names from the [palette]. You can
extend an existing theme with inherits = "boo_berry".
Note
The names
defaultandbase16_defaultare reserved built-ins and cannot be overridden. Helix does not support transparency (no alpha channel). The full list of themeable scopes (syntax and UI) is documented in the Helix Admin Guide.
17. Configuring Languages and Language Servers
Language-specific behavior — which language server to use, indentation, formatters, file-type
detection — is set in languages.toml. There are three locations, merged in order of
increasing precedence:
- Built-in defaults (shipped with Helix).
- Your config directory:
~/.config/helix/languages.toml. - Project-local:
<project>/.helix/languages.toml.
Overriding a language
# ~/.config/helix/languages.toml
[[language]]
name = "rust"
auto-format = false
indent = { tab-width = 4, unit = " " }
Commonly used [[language]] keys:
| Key | Description |
|---|---|
name |
Language name (must match a known language) |
file-types |
Extensions or globs that select this language |
auto-format |
Format this language on save |
comment-tokens |
Comment token(s), e.g. "//" or ["//", "///"] |
indent |
{ unit = " ", tab-width = 2 } |
language-servers |
Which servers handle this language |
formatter |
External formatter command (takes stdin, writes stdout) |
roots |
Marker files used for LSP root detection (e.g. Cargo.toml) |
Configuring a language server
[language-server.mylang-lsp]
command = "mylang-lsp"
args = ["--stdio"]
config = { provideFormatter = true }
environment = { "ENV1" = "value1" }
[[language]]
name = "mylang"
language-servers = ["mylang-lsp"]
A language can use multiple servers, and you can enable or disable individual features per
server with only-features / except-features:
[[language]]
name = "typescript"
language-servers = [
{ name = "efm-lsp-prettier", only-features = ["format"] },
"typescript-language-server",
]
File-type detection
file-types accepts plain extensions and glob tables (matched against the full path,
always using / as the separator even on Windows):
file-types = ["toml", { glob = "Makefile" }, { glob = ".github/workflows/*.yaml" }]
Globs take priority over extension matches.
Tree-sitter grammars
Grammars are declared in [[grammar]] sections and fetched/built with
hx --grammar fetch and hx --grammar build. To limit which grammars are processed, set a
top-level use-grammars key before any [[language]] or [[grammar]] section:
use-grammars = { only = ["rust", "c", "cpp"] }
# or
use-grammars = { except = ["yaml", "json"] }
Tip
Change a single buffer's language on the fly with
:set-language <name>(:lang). Run:langwith no argument to see the current language.
18. Workspace Trust
Because LSP and project-local configuration can execute code, Helix gates them behind a workspace trust mechanism. No workspace is trusted by default.
- When you open a file in a new, undecided workspace, Helix prompts you about trust.
- Choosing Never excludes the workspace so you are not prompted again.
:workspace-trusttrusts the current workspace;:workspace-untrustrevokes it.
Trusted and excluded workspaces are stored (newline-delimited) in
~/.local/share/helix/trusted_workspaces and .../excluded_workspaces.
Caution
You can restore the old, unguarded behavior — loading every
.helix/config.tomland starting language servers without permission — by settingeditor.insecure = true. Only do this if you understand the code-execution risk.
19. Migrating from Vim
The biggest adjustment is the selection → action order. In Vim you say "delete a word"
(dw); in Helix you "select a word, then delete" (wd). Here are the most common
translations:
| Task | Vim | Helix |
|---|---|---|
| Delete a word | dw |
wd |
| Change a word | cw |
wc or ec |
| Delete a character | x |
d (or ;d) |
| Delete an entire line | dd |
xd |
| Copy a line | yy |
Xy |
| Go to last line | G |
ge |
| Go to line start / end | 0 / $ |
gh / gl |
| First non-blank | ^ |
gs |
| Jump to matching bracket | % |
mm |
| Select whole file | ggVG |
% |
| Comment lines | gc |
Space c |
| Autocomplete | Ctrl-p |
Ctrl-x |
| Global replace | :%s/foo/bar/g |
%sfoo<ret>cbar<esc>, |
| Replace in selection | :s/foo/bar/g |
sfoo<ret>cbar<esc>, |
| Reload file | :e |
:reload |
| Run shell command | :!cmd |
:sh cmd (or !cmd to insert output) |
Note
Helix has no block-selection mode. Use multiple cursors instead: add cursors on lines below with
C, then move them together. There are no named bookmarks; save a location to the jumplist withCtrl-sand return viaCtrl-o/Ctrl-ior the jumplist picker (Space j).
20. Troubleshooting
The following entries combine Helix's documented behavior with real issues reported by the community.
Error: keys seem to insert random commands instead of text
Cause: You are in normal mode, where letter keys run commands.
Solution: Press Esc to ensure you are in normal mode, then press i to enter insert
mode before typing.
Prevention: Watch the mode indicator on the status line (NOR, INS, SEL).
Error: hx: command not found
Cause: The binary is not on your $PATH, or your package manager installed it as
helix (notably Arch's extra repository).
Solution: Try running helix. Otherwise add the install location to $PATH. Verify with
hx --health (or helix --health).
Prevention: When using pre-built binaries or AppImages, install hx into a directory
already on your PATH such as ~/.local/bin.
Error: syntax highlighting or indentation is missing
Cause: The tree-sitter grammar for the language isn't built, or runtime files aren't
found.
Solution: Run hx --health <language> to check. Fetch and build grammars with
hx --grammar fetch && hx --grammar build, and confirm HELIX_RUNTIME points to a valid
runtime directory.
Prevention: When building from source, always configure the runtime directory (see
Building from source).
Error: language server features (gd, hover, completion) do nothing
Cause: No language server is installed/on PATH, or the workspace is untrusted.
Solution: Install the appropriate server and ensure it is on $PATH. Run hx --health
to confirm Helix detects it. Trust the workspace if prompted (:workspace-trust). Restart
the server with :lsp-restart.
Prevention: Consult the
Language Server Configurations wiki.
Error: some keybindings don't work in my terminal
Cause: Your terminal intercepts certain key combinations, or lacks support for the
enhanced keyboard protocol (this affects Shift-Tab, Super-key bindings, and some Alt
combinations).
Warning
A known long-standing example is
Alt/Opt+_not working on macOS (#2280). This is generally a terminal-level key-handling limitation rather than a Helix bug.
Solution: Check your terminal's key mappings for conflicts and, where available, enable the enhanced/Kitty keyboard protocol. See the Terminal Support wiki. Prevention: Prefer a terminal with good protocol support (e.g. Kitty, WezTerm, recent Alacritty/foot) for the smoothest binding experience.
Error: the editor crashed or panicked
Cause: Certain edge cases have produced panics — for example navigating the jumplist
after :reload-all (#13149) or
specific selection/change interactions
(#12582). Several such cases have been
fixed in recent releases.
Solution: Update to the latest release or nightly. If it still reproduces, capture the
log (hx -v for more verbosity, or :log-open) and file an issue with steps to reproduce.
Prevention: Keep Helix current; many crash fixes ship in each release.
Error: opening a directory misbehaves
Cause: Passing a directory to hx opens the file picker / explorer; some platform edge
cases have been reported (#14785).
Solution: Open a specific file, or use Space f from within Helix. Update to the latest
version.
Where is the log file?
Open it with :log-open, or start Helix with a custom path: hx --log /tmp/helix.log and
tail -f /tmp/helix.log in another terminal. Increase verbosity with repeated -v flags
(hx -vv).
21. Frequently Asked Questions
Q: Do I need to install plugins to be productive? No. LSP, tree-sitter syntax highlighting, multiple cursors, fuzzy pickers, and a debugger client are all built in. A formal plugin system is planned but not required for everyday use.
Q: How do I learn the editing model quickly?
Run hx --tutor (or :tutor). It is an interactive, hands-on tutorial and the fastest way
to internalize selection-first editing.
Q: How do I save and quit?
:w saves, :q quits, :wq (or :x) does both. :wqa saves all buffers and closes all
views.
Q: Why don't :%s/foo/bar/ and other :substitute-style commands exist?
Helix expresses replacement through multiple selections: %sfoo<ret>cbar<esc>,. See
Search and Replace.
Q: How do I copy to the system clipboard?
Use space-mode clipboard commands: Space y to yank, Space p/Space P to paste. Or yank
to the + register directly ("+y).
Q: How do I change the theme without editing my config?
Run :theme <name> and use Tab to browse available themes interactively.
Q: Where do my config files go?
~/.config/helix/config.toml and languages.toml on Linux/macOS;
%AppData%\helix\ on Windows. Project-local overrides go in a .helix/ folder.
Q: How do I reload my config without restarting?
:config-reload. On Unix you can also send USR1: pkill -USR1 hx.
Q: Can I use Helix like a non-modal editor?
Insert mode includes a few movement and editing keys (arrows, Ctrl-w to delete a word) for
newcomers, but Helix is designed around modal editing and you will get the best experience by
learning it. You can disable the insert-mode arrow keys once comfortable.
Q: How do I add a trailing character to many lines at once?
x to select a line (repeat to extend), or % for the whole file, then Alt-s to split on
newlines (a cursor per line), then A, type the character, Esc.
Q: How do I see every command and its keybinding?
Open the command palette with Space ?, or consult the Reference below.
Q: What languages are supported? Several hundred, via tree-sitter grammars, with language-server support for most mainstream languages. See the language support matrix.
Q: My Alt/Shift/Super keybindings don't register — is Helix broken? Usually not. This is a terminal key-handling limitation. Enable the enhanced keyboard protocol in your terminal where possible, and check the Terminal Support wiki.
22. Reference
Command-line flags
hx [FLAGS] [files] — open files by passing paths. A path may include a position:
file.rs:10:2 opens at line 10, column 2; +N file opens at line N; + opens at the last
line.
| Flag | Description |
|---|---|
-h, --help |
Print help |
-V, --version |
Print version |
--tutor |
Open the interactive tutorial |
--health [LANG] |
Print health info (optionally for one language) |
-g, --grammar fetch |
Fetch tree-sitter grammars |
-g, --grammar build |
Build tree-sitter grammars |
-c, --config <PATH> |
Use a specific config file |
--log <PATH> |
Write the log to a specific path |
-w, --working-dir <PATH> |
Set the initial working directory |
--vsplit |
Open files in vertical splits |
--hsplit |
Open files in horizontal splits |
--strict |
Enforce strict parsing (fail on unknown config) |
-v |
Increase verbosity (repeatable: -vv, -vvv) |
-- |
Treat all following arguments as file paths |
Keymap reference
Bindings marked (LSP) require a language server; (TS) require a tree-sitter grammar.
Movement (normal mode)
| Key | Command | Key | Command |
|---|---|---|---|
h Left |
move left | l Right |
move right |
j Down |
move down (visual line) | k Up |
move up (visual line) |
w / b / e |
next/prev word start, next word end | W / B / E |
same for WORDs |
f / t |
find / till next char | F / T |
find / till previous char |
<n>G, <n>gg |
go to line <n> |
Alt-. |
repeat last motion |
Ctrl-u / Ctrl-d |
half page up / down | Ctrl-b / Ctrl-f |
page up / down |
Ctrl-i / Ctrl-o |
jump forward / backward | Ctrl-s |
save selection to jumplist |
Home / End |
line start / end |
Changes (normal mode)
| Key | Command | Key | Command |
|---|---|---|---|
r |
replace char | R |
replace with yanked |
i / a |
insert before / after | I / A |
insert at line start / end |
o / O |
open line below / above | . |
repeat last insert |
u / U |
undo / redo | Alt-u / Alt-U |
earlier / later in history |
y / p / P |
yank / paste after / before | "<reg> |
select register |
> / < |
indent / unindent | = |
format (LSP) |
d / Alt-d |
delete / delete no-yank | c / Alt-c |
change / change no-yank |
Ctrl-a / Ctrl-x |
increment / decrement | Ctrl-c |
toggle comments |
~ / ` / Alt-` |
toggle / lower / upper case | J |
join lines |
Q / q |
record / replay macro |
Selection manipulation
| Key | Command | Key | Command |
|---|---|---|---|
s |
select regex matches | S |
split on regex |
Alt-s |
split on newlines | & |
align in columns |
_ |
trim whitespace | ; |
collapse to cursor |
Alt-; |
flip cursor/anchor | , / Alt-, |
keep / remove primary |
C / Alt-C |
add cursor below / above | ( / ) |
rotate primary back / forward |
Alt-( / Alt-) |
rotate contents back / forward | % |
select whole file |
x / X |
extend line below / to bounds | Alt-x |
shrink to line bounds |
K / Alt-K |
keep / remove matching regex | J |
join lines |
Alt-o / Alt-i |
expand / shrink syntax node (TS) | Alt-p / Alt-n |
prev / next sibling (TS) |
Minor-mode entry keys (normal mode)
| Key | Enters | Key | Enters |
|---|---|---|---|
v |
select/extend mode | g |
goto mode |
m |
match mode | : |
command mode |
z / Z |
view / sticky view mode | Ctrl-w |
window mode |
Space |
space mode |
Goto mode (g)
| Key | Goes to | Key | Goes to |
|---|---|---|---|
g |
file start (or line <n>) |
e |
file end |
h / l |
line start / end | s |
first non-whitespace |
d (LSP) |
definition | y (LSP) |
type definition |
r (LSP) |
references | i (LSP) |
implementation |
t / c / b |
window top / center / bottom | a / m |
last accessed / modified file |
n / p |
next / previous buffer | . |
last modification |
f |
file/URL under selection | w |
jump to a two-char label |
Space mode (Space) — pickers and LSP
| Key | Action | Key | Action |
|---|---|---|---|
f / F |
file picker (root / cwd) | b |
buffer picker |
j |
jumplist picker | g |
changed-file picker |
s / S |
document / workspace symbols | d / D |
document / workspace diagnostics |
k (LSP) |
hover docs | r (LSP) |
rename symbol |
a (LSP) |
code action | h (LSP) |
select symbol references |
/ |
global search | ? |
command palette |
y / Y |
yank to clipboard / main to clipboard | p / P |
paste clipboard after / before |
R |
replace from clipboard | ' |
last picker |
c / C |
comment / block-comment | w |
window mode |
View mode (z / sticky Z)
| Key | Action | Key | Action |
|---|---|---|---|
z/c |
center line | t / b |
align top / bottom |
j / k |
scroll down / up | Ctrl-d / Ctrl-u |
half page down / up |
Match mode (m)
| Key | Action |
|---|---|
m |
go to matching bracket (TS) |
s<char> |
surround add |
r<from><to> |
surround replace |
d<char> |
surround delete |
a<object> / i<object> |
select around / inside textobject |
Window mode (Ctrl-w)
| Key | Action | Key | Action |
|---|---|---|---|
v / s |
vertical / horizontal split | q / o |
close / close others |
h/j/k/l |
move between splits | H/J/K/L |
swap splits |
w |
next window |
Insert-mode keys
| Key | Action | Key | Action |
|---|---|---|---|
Esc |
normal mode | Ctrl-x |
autocomplete |
Ctrl-r |
insert register | Ctrl-w / Alt-Backspace |
delete previous word |
Alt-d |
delete next word | Ctrl-u / Ctrl-k |
delete to line start / end |
Ctrl-s |
commit undo checkpoint | Tab / Shift-Tab |
smart-tab / insert tab |
Unimpaired (bracket) motions
| Key | Goes to | Key | Goes to |
|---|---|---|---|
]d / [d (LSP) |
next / prev diagnostic | ]f / [f (TS) |
next / prev function |
]t / [t (TS) |
next / prev type | ]a / [a (TS) |
next / prev argument |
]c / [c (TS) |
next / prev comment | ]T / [T (TS) |
next / prev test |
]p / [p |
next / prev paragraph | ]g / [g |
next / prev change |
]Space / [Space |
add line below / above |
Typable command reference
Run these from the command line (:). Aliases are shown after the canonical name.
| Command | Aliases | Description |
|---|---|---|
:quit |
:q |
Close the current view |
:quit! |
:q! |
Force close, discarding changes |
:open |
:o, :edit, :e |
Open a file |
:write |
:w |
Write changes to disk (optional path) |
:write! |
:w! |
Write, creating directories |
:write-quit |
:wq, :x |
Write and close the view |
:write-quit-all |
:wqa, :xa |
Write all and close all views |
:write-all |
:wa |
Write all buffers |
:quit-all |
:qa |
Close all views |
:update |
:u |
Write only if modified |
:new |
:n |
Create a new scratch buffer |
:reload |
:rl |
Discard changes, reload from disk |
:reload-all |
:rla |
Reload all documents |
:buffer-close |
:bc, :bclose |
Close the current buffer |
:buffer-next / :buffer-previous |
:bn / :bp |
Next / previous buffer |
:format |
:fmt |
Format with formatter or LSP |
:vsplit / :hsplit |
:vs / :hs, :sp |
Open file in vertical / horizontal split |
:goto |
:g |
Go to a line number |
:theme |
Change the theme (shows current if no name) | |
:set-option |
:set |
Set a config option at runtime |
:toggle-option |
:toggle |
Toggle a config option |
:get-option |
:get |
Read a config option's value |
:set-language |
:lang |
Set the buffer's language |
:config-open / :config-reload |
Open / reload your config | |
:config-open-workspace |
Open the workspace config | |
:log-open |
Open the Helix log file | |
:sort |
Sort ranges in the selection (--reverse to flip) |
|
:reflow |
Hard-wrap selected lines to a width | |
:indent-style |
Set indentation (t for tabs, or 1–16 spaces) |
|
:line-ending |
Set line ending (crlf / lf) |
|
:encoding |
Set the file encoding | |
:earlier / :later |
:ear / :lat |
Jump back / forward in edit history |
:clipboard-yank / :clipboard-paste-after |
System-clipboard yank / paste | |
:lsp-restart / :lsp-stop |
Restart / stop language servers | |
:lsp-workspace-command |
Open the workspace command picker | |
:pipe / :pipe-to |
:| |
Pipe selections to a shell command |
:insert-output / :append-output |
Run a command, insert / append output | |
:run-shell-command |
:sh, :! |
Run a shell command |
:tutor |
Open the tutorial | |
:change-current-directory |
:cd |
Change the working directory |
:show-directory |
:pwd |
Show the working directory |
:move |
:mv |
Move the buffer and its file to a new path |
:read |
:r |
Read a file into the buffer |
:set-register / :clear-register |
Set / clear a register | |
:character-info |
:char |
Info about the character under the cursor |
:workspace-trust / :workspace-untrust |
Trust / untrust the current workspace | |
:cquit |
:cq |
Quit with an exit code |
:redraw |
Re-render the whole UI | |
:echo / :noop |
Print to the statusline / do nothing |
Note
This is the everyday subset. Every command also appears in the in-editor command palette (
Space ?), which always reflects your exact version, including debugger (:debug-*) and tree-sitter inspection (:tree-sitter-*) commands.
Static command reference
Static commands are the building blocks you bind keys to (see
Key Remapping). They number in the hundreds; below is an
orientation by category. For the complete list with current default bindings, open the
command palette (Space ?) or see the source static_commands! macro in
helix-term/src/commands.rs.
| Category | Representative commands |
|---|---|
| Movement | move_char_left/right, move_next_word_start, move_prev_word_end, goto_line |
| Extension (select) | extend_char_left/right, extend_next_word_start, extend_to_line_bounds |
| Sub-word movement | move_next_sub_word_start, move_prev_sub_word_end (unbound by default) |
| Changes | delete_selection, change_selection, replace, undo, redo, indent |
| Selection | select_regex, split_selection, keep_selections, align_selections |
| Syntax (TS) | expand_selection, shrink_selection, select_next_sibling, match_brackets |
| Search | search, search_next, global_search, search_selection |
| Clipboard/registers | yank, yank_to_clipboard, paste_after, select_register, insert_register |
| LSP | goto_definition, hover, code_action, rename_symbol, signature_help |
| Pickers | file_picker, buffer_picker, command_palette, jumplist_picker |
| Windows | vsplit, hsplit, jump_view_left, swap_view_down, wclose |
| Shell | shell_pipe, shell_insert_output, shell_keep_pipe, suspend |
| Debugger (DAP) | dap_launch, dap_toggle_breakpoint, dap_continue, dap_step_in |
| Misc | no_op, increment, decrement, record_macro, replay_macro, goto_word |
Language support
Helix supports several hundred languages through tree-sitter, with per-language capabilities that vary across syntax highlighting, tree-sitter textobjects, auto-indent, code navigation tags, rainbow brackets, and default language servers. A few examples:
| Language | Highlight | Textobjects | Auto-indent | Default LSP |
|---|---|---|---|---|
| Rust | ✓ | ✓ | ✓ | rust-analyzer |
| C / C++ | ✓ | ✓ | ✓ | clangd |
| Go | ✓ | ✓ | ✓ | gopls |
| Python | ✓ | ✓ | ✓ | pylsp / ruff |
| TypeScript | ✓ | ✓ | ✓ | typescript-language-server |
| Bash | ✓ | ✓ | ✓ | bash-language-server |
To see the full, version-accurate matrix for your build, consult the generated language
support page in the Helix book, or run hx --health <language> for a specific language.