vimtricks.wiki Concise Vim tricks, one at a time.

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:

  1. tmux — splits a pane for the job (preferred in terminal workflows)
  2. iTerm — uses iTerm2 tabs on macOS
  3. screen — uses GNU screen splits
  4. headless — uses Vim's built-in job control as a fallback

Tips

  • Map :Make to a key for instant access: nnoremap <F5> :Make<CR>
  • Map :Dispatch for 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 :copen to 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 / [q to navigate errors efficiently after a build completes

Next

How do I edit multiple lines at once using multiple cursors in Vim?