How do I run builds and tests asynchronously without blocking Vim?
Answer
:Make / :Dispatch
Explanation
The vim-dispatch plugin by Tim Pope provides asynchronous build and command execution so you can run compilers, test suites, and other long-running commands without freezing your editor. Instead of staring at a blank screen while :make runs synchronously, dispatch sends the job to the background and populates the quickfix list when it finishes.
The problem
Vim's built-in :make command blocks the entire editor until the process completes. For projects with slow builds or large test suites, this means you sit idle for seconds or minutes. Vim-dispatch solves this by running commands asynchronously using tmux, screen, iTerm, or a built-in terminal.
Core commands
:Make " async version of :make — runs &makeprg in the background
:Make! " same as :Make but don't jump to the first error
:Dispatch command " run any shell command asynchronously
:Dispatch! " run without jumping to results
:Start command " open a command in a new terminal window
:Start! " open a command in the background
How :Make works
:Make runs whatever makeprg is set to for the current filetype, parses the output using errorformat, and loads the results into the quickfix list. When the build finishes, you get a notification and can navigate errors with ]q and [q (via vim-unimpaired) or :cnext and :cprev.
" For a Go project:
set makeprg=go\ build\ ./...
:Make
" For a JavaScript project:
set makeprg=npm\ test
:Make
Using :Dispatch for arbitrary commands
:Dispatch runs any shell command and intelligently parses the output:
:Dispatch rspec % " run rspec on the current file
:Dispatch pytest %:p " run pytest on the current file
:Dispatch go test ./... " run all Go tests
:Dispatch cargo build " build a Rust project
:Dispatch npm run lint " run a linter
Dispatch auto-detects the appropriate compiler plugin when possible, so error parsing just works.
Setting a default dispatcher per file
Use b:dispatch to set a default command for the current buffer:
autocmd FileType ruby let b:dispatch = 'ruby %'
autocmd FileType python let b:dispatch = 'python3 %'
autocmd FileType go let b:dispatch = 'go test ./...'
Then pressing :Dispatch with no arguments runs the buffer's default command.
Focus command
The :FocusDispatch command lets you set a persistent dispatch target that overrides b:dispatch:
:FocusDispatch rspec spec/models/user_spec.rb
:Dispatch " now always runs the focused command
:FocusDispatch! " clear the focus
This is perfect when you are working across multiple files but want to re-run the same test repeatedly.
Adapter priority
Dispatch automatically selects the best adapter for your environment:
- tmux — splits a pane for the job (preferred in terminal workflows)
- iTerm — uses iTerm2 tabs on macOS
- screen — uses GNU screen splits
- headless — uses Vim's built-in job control as a fallback
Tips
- Map
:Maketo a key for instant access:nnoremap <F5> :Make<CR> - Map
:Dispatchfor running tests:nnoremap <Leader>t :Dispatch<CR> - Dispatch integrates with vim-projectionist for per-project command configuration
- The quickfix list auto-opens when errors are found — use
:copento view it manually - Use
:Copen(provided by dispatch) to open the quickfix list with the full raw output of the last build - Combine with vim-unimpaired's
]q/[qto navigate errors efficiently after a build completes