Vim Docker Integration: Complete Guide
Working with Docker containers often means juggling between terminal sessions, copying files in and out of containers, and struggling with limited tooling inside minimal images. Vim, the ubiquitous text editor, can become your secret weapon for seamless Docker workflows — whether you're editing files inside running containers, developing Dockerfiles efficiently, or running Vim itself inside a containerized environment. This guide walks through everything you need to know.
What Is Vim Docker Integration?
Vim Docker integration refers to the set of techniques, plugins, and workflows that allow Vim (or Neovim) to interact smoothly with Docker containers. This includes editing files that live inside containers, using Vim as your editor for docker commit operations, running Vim inside containers for debugging, and leveraging Vim plugins that understand Dockerfile syntax and container lifecycles.
At its core, the integration is about removing friction. Instead of copying files out of a container, editing them locally, and copying them back, you can edit in place. Instead of fighting with missing editors inside Alpine-based images, you can establish a consistent editing environment.
Why It Matters
- Speed: Editing files directly inside containers eliminates round-trip file transfers.
- Consistency: A containerized Vim configuration travels with your project, ensuring every team member has the same editing experience.
- Debugging: When troubleshooting a running container, having a capable editor available inside it is invaluable.
- Reproducibility: Bundling Vim and its config into a Docker image makes your development environment fully reproducible.
- Remote development: Running Vim inside a container on a remote host gives you a powerful editor without local installation overhead.
Editing Files Inside Running Containers
The simplest form of integration is editing files that exist inside a running container. Docker provides a cp command, but a more elegant approach uses docker exec combined with an editor. However, many minimal images don't include Vim. The workaround is to copy the file out, edit locally, and copy it back — or mount a volume.
Here's a shell function that automates the round-trip editing pattern:
# Add to your ~/.bashrc or ~/.zshrc
docker-vim() {
if [ -z "$1" ] || [ -z "$2" ]; then
echo "Usage: docker-vim <container> <file-path>"
return 1
fi
local container="$1"
local filepath="$2"
local filename=$(basename "$filepath")
local tmpfile=$(mktemp "/tmp/docker-vim-${filename}.XXXXXX")
docker cp "${container}:${filepath}" "$tmpfile"
vim "$tmpfile"
docker cp "$tmpfile" "${container}:${filepath}"
rm -f "$tmpfile"
}
After sourcing your shell configuration, you can run docker-vim my_container /etc/nginx/nginx.conf to edit the file with your local Vim configuration and have changes pushed back automatically.
Using Vim as the Default Editor for Docker Operations
Docker doesn't have a built-in "edit" command, but you can configure your environment so that any tooling that invokes an editor — such as docker commit change messages or compose file generators — uses Vim. Set the EDITOR and VISUAL environment variables:
export EDITOR=vim
export VISUAL=vim
For tools that spawn an editor inside a container, pass the environment variable through:
docker run -it --rm -e EDITOR=vim my-image /bin/sh
Running Vim Inside a Container
Sometimes you need Vim available inside the container itself — for example, when debugging network-isolated environments or when the container filesystem is complex. The challenge is that most production images are minimal. You have two main strategies: install Vim at runtime, or bake it into a development image.
Strategy 1: Install at Runtime
For quick debugging sessions, install Vim on the fly. This is ephemeral and won't persist after the container is removed:
# Alpine-based images
docker exec -it my_container sh -c "apk add --no-cache vim && vim"
# Debian/Ubuntu-based images
docker exec -it my_container sh -c "apt-get update && apt-get install -y vim && vim"
Strategy 2: Build a Development Image
For a more robust setup, create a dedicated development Dockerfile that extends your production image with Vim and your configuration:
FROM my-app:latest
# Install Vim
RUN apt-get update && \
apt-get install -y --no-install-recommends vim && \
rm -rf /var/lib/apt/lists/*
# Copy your Vim configuration
COPY .vimrc /root/.vimrc
COPY .vim /root/.vim
# Install plugin manager if needed
RUN vim +PlugInstall +qall || true
WORKDIR /app
CMD ["vim"]
Build and run it:
docker build -t my-app:dev -f Dockerfile.dev .
docker run -it --rm \
-v $(pwd):/app \
-v my-app-vim-cache:/root/.vim/cache \
my-app:dev
Mounting Your Local Vim Configuration Into Containers
If you don't want to bake your config into an image, you can mount your local Vim files as volumes. This keeps your configuration centralized on your host while making it available inside any container:
docker run -it --rm \
-v $(pwd):/workspace \
-v ~/.vimrc:/root/.vimrc:ro \
-v ~/.vim:/root/.vim:ro \
-v ~/.vim/bundle:/root/.vim/bundle \
-w /workspace \
alpine sh -c "apk add --no-cache vim && vim"
Note the :ro flag on the config files — this prevents the container from accidentally modifying your host configuration. The bundle directory is mounted read-write so plugins can update their caches.
Neovim and Docker: A Modern Approach
Neovim offers better integration opportunities thanks to its built-in terminal emulator and remote plugin architecture. You can run Neovim in a container and connect to it, or use Neovim's terminal to manage Docker sessions. A popular pattern is to run Neovim as a containerized development environment:
# Dockerfile.nvim
FROM ubuntu:22.04
RUN apt-get update && apt-get install -y \
neovim \
git \
curl \
ripgrep \
nodejs \
npm \
&& rm -rf /var/lib/apt/lists/*
RUN curl -fLo ~/.local/share/nvim/site/autoload/plug.vim --create-dirs \
https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim
COPY init.lua /root/.config/nvim/init.lua
WORKDIR /workspace
CMD ["nvim"]
Run it with your project mounted:
docker run -it --rm \
-v $(pwd):/workspace \
-v nvim-data:/root/.local/share/nvim \
my-nvim:latest
Vim Plugins for Docker Development
Several Vim plugins enhance Docker-specific workflows. Here are the most useful ones:
1. vim-dockerfile-syntax
Provides proper syntax highlighting and indentation for Dockerfiles. Most modern Vim distributions include this, but if not:
" .vimrc
Plug 'ekalinin/Dockerfile.vim'
2. vim-docker (Async Commands)
Lets you run Docker commands asynchronously from within Vim, so you can build images without blocking the editor:
Plug 'skanehira/docker.vim'
With this plugin, you can use commands like :DockerImageList, :DockerContainerList, and :DockerImageBuild directly from Vim.
3. ALE (Asynchronous Lint Engine)
ALE can lint Dockerfiles using hadolint, catching common mistakes before you build:
Plug 'dense-analysis/ale'
let g:ale_linters = {
\ 'dockerfile': ['hadolint'],
\}
Install hadolint on your host or mount it into your container, and ALE will highlight issues as you type.
Editing Docker Compose Files Efficiently
Compose files are YAML, and Vim handles YAML well out of the box. To improve the experience, add these settings to your .vimrc:
" YAML-specific settings
autocmd FileType yaml setlocal ts=2 sts=2 sw=2 expandtab
autocmd FileType yaml setlocal foldmethod=indent foldlevel=1
" Auto-reload compose file detection
autocmd BufRead,BufNewFile docker-compose*.yml set filetype=yaml.docker-compose
You can also define a custom command to validate compose files from within Vim:
command! ComposeValidate :!docker compose config --quiet
command! ComposeUp :!docker compose up -d
command! ComposeDown :!docker compose down
Remote Editing with Vim and Docker Volumes
A powerful pattern for remote development is running Vim on your host while the application runs in a container, sharing a named volume. This gives you full local Vim performance while the container sees live file changes:
# Create a named volume
docker volume create app-source
# Run the application container with the volume
docker run -d --name my-app \
-v app-source:/app \
my-app:latest
# Run a sidecar Vim container that shares the same volume
docker run -it --rm \
-v app-source:/workspace \
-v ~/.vimrc:/root/.vimrc:ro \
my-vim:latest
Now edits made in the Vim container are immediately visible to the application container, enabling true hot-reload development.
Best Practices
- Keep images small: Only install Vim in development images, never in production. Use multi-stage builds to ensure the final image stays lean.
- Use read-only mounts for configs: When mounting your
.vimrcinto containers, use:roto prevent accidental modification. - Persist plugin data: Mount a named volume for Vim cache and plugin directories so you don't reinstall plugins every time.
- Version your Vim config: Store your Vim configuration in a Git repository and reference it in your Dockerfile. This ensures reproducibility across team members.
- Leverage async tools: Use ALE or async build plugins to run
docker buildwithout freezing your editor session. - Use terminal multiplexers: Pair Vim with tmux inside containers to maintain editing sessions even if your SSH connection drops.
- Secure sensitive files: Be cautious when mounting
.vimrcfiles that might contain credentials or paths — use environment-specific configs when needed. - Test your Dockerfiles with hadolint: Integrate linting into your Vim workflow so errors are caught before you ever run
docker build.
A Complete Development Dockerfile Example
Putting it all together, here's a complete development Dockerfile that bundles Vim with a typical web development setup:
FROM node:20-alpine
# Install Vim and useful tools
RUN apk add --no-cache \
vim \
git \
ripgrep \
bash \
curl
# Set Vim as default editor
ENV EDITOR=vim
ENV VISUAL=vim
# Copy Vim configuration
COPY vimrc /root/.vimrc
# Install vim-plug
RUN curl -fLo /root/.vim/autoload/plug.vim --create-dirs \
https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim
# Install plugins silently
RUN vim +PlugInstall +qall >/dev/null 2>&1 || true
WORKDIR /app
EXPOSE 3000
CMD ["vim"]
And the accompanying vimrc for the container:
set nocompatible
syntax on
filetype plugin indent on
set number
set tabstop=2
set shiftwidth=2
set expandtab
set autoindent
set smartindent
set hlsearch
set incsearch
set ignorecase
set smartcase
call plug#begin('~/.vim/plugged')
Plug 'pangloss/vim-javascript'
Plug 'maxmellon/vim-jsx-pretty'
Plug 'dense-analysis/ale'
Plug 'tpope/vim-fugitive'
call plug#end()
let g:ale_linters = {
\ 'javascript': ['eslint'],
\ 'dockerfile': ['hadolint'],
\}
Conclusion
Vim and Docker are a surprisingly powerful combination. By understanding the various integration points — from editing files inside running containers to running Vim itself in a containerized environment — you can build a development workflow that is fast, consistent, and fully reproducible. Whether you choose to mount your local configuration, bake Vim into a development image, or use async plugins to manage Docker from within the editor, the key is to match the approach to your team's needs. Start with the simple round-trip editing function, graduate to a dedicated development Dockerfile, and layer in plugins as your workflow demands. With these techniques in your toolkit, containerized development with Vim becomes not just viable, but genuinely enjoyable.