Use your preferred editor (Vim, Emacs, Neovim, Claude Code, ...) with all OCaml tools running inside the container.
- Docker installed and running
- Node.js (for the DevContainer CLI)
- DevContainer CLI:
npm install -g @devcontainers/cli
Permission error? If
npm install -gfails with EACCES, either configure npm's default directory or install with your system package manager (e.g.sudo apt install nodejs npm).
Podman alternative: On macOS, Podman works as a drop-in replacement for Docker Desktop. Install it via
brew install podman, then create adockeralias so the DevContainer CLI finds it:sudo ln -s $(which podman) /usr/local/bin/dockerSee From Docker to Podman: VS Code DevContainers for details.
git clone https://github.com/tarides/ocaml-devcontainer.git
cd ocaml-devcontainer
devcontainer up --workspace-folder .
# Run commands inside the container
devcontainer exec --workspace-folder . dune buildRun your editor inside the container where all OCaml tools are available:
devcontainer exec --workspace-folder . vim src/main.ml
devcontainer exec --workspace-folder . emacs src/main.ml
devcontainer exec --workspace-folder . nvim src/main.ml
devcontainer exec --workspace-folder . claudeAdd to your shell config for convenience:
alias dc='devcontainer exec --workspace-folder .'
# Then:
dc dune build
dc vim src/main.mlFor ThreadSanitizer support, use the TSan devcontainer configuration:
devcontainer up --workspace-folder . --config .devcontainer-tsan/devcontainer.json
devcontainer exec --workspace-folder . bash -c 'opam switch ocaml+tsan && eval $(opam env) && dune build'See the README for details.
docker stop $(docker ps -q --filter "label=devcontainer.local_folder=$(pwd)")The workspace folder is mounted from your host, so your files are always safe on disk. State inside the container (installed packages, shell history) persists across docker stop/devcontainer up cycles as long as the container is not removed. Running docker rm or devcontainer up --remove-existing-container destroys that state.
Edit files remotely using Emacs TRAMP with the Docker method.
-
Start the container:
devcontainer up --workspace-folder . -
Find the container name:
docker ps --filter "label=devcontainer.local_folder=$(pwd)" --format '{{.Names}}'
-
In Emacs, open files with:
C-x C-f /docker:CONTAINER_NAME:/home/vscode/project/src/main.ml -
Configure eglot for LSP support — add to your Emacs config:
(add-to-list 'eglot-server-programs '(tuareg-mode . ("docker" "exec" "-i" "CONTAINER_NAME" "ocamllsp")))
Neovim plugins
For a VS Code-like "Reopen in Container" experience:
- Install nvim-dev-container
- Configure in your init.lua:
require('devcontainer').setup({})
- Use
:DevcontainerStartto open in container
Manual LSP setup
vim.api.nvim_create_autocmd('FileType', {
pattern = 'ocaml',
callback = function()
vim.lsp.start({
name = 'ocamllsp',
cmd = { 'docker', 'exec', '-i', 'CONTAINER_NAME', 'ocamllsp' },
root_dir = vim.fs.dirname(vim.fs.find({'dune-project'}, {upward = true})[1]),
})
end,
})- Works with any editor — no special plugins required
- Consistent environment — same tools, same versions, every time
- No host pollution — OCaml tools stay in the container
- Easy to teach — one pattern for all editors
See the README for installed tools, common commands, and switch details.