FreeBSD.software
Home/Guides/How to Set Up a FreeBSD Development Environment
tutorial·2026-04-09·11 min read

How to Set Up a FreeBSD Development Environment

Set up a complete development environment on FreeBSD: compilers (clang, gcc), editors (Neovim, VS Code), Git, Python, Rust, Go, Node.js, Docker alternatives with jails, and tmux workflow.

How to Set Up a FreeBSD Development Environment

FreeBSD ships with a minimal base system. Turning it into a productive development environment requires installing compilers, language runtimes, editors, version control, and workflow tools. This is straightforward -- FreeBSD's package repository contains everything you need -- but the choices and configuration differ from Linux in ways that matter.

This guide covers a complete development environment setup on FreeBSD 14.x: C/C++ compilers, Python, Rust, Go, Node.js, editors (Neovim and VS Code), Git configuration, container alternatives with jails, tmux workflow, and FreeBSD-specific development considerations.

For package management background, see our FreeBSD pkg vs ports guide.

Base Development Tools

FreeBSD includes Clang/LLVM in the base system. It is the default system compiler and builds the kernel and world. You do not need to install it separately.

Verify the base compiler:

sh
cc --version c++ --version

Install additional build tools:

sh
pkg install gmake cmake ninja autoconf automake libtool pkgconf

FreeBSD uses make for BSD make (the base system build tool) and gmake for GNU make. Most open-source projects expect GNU make. If a project's Makefile fails with BSD make, use gmake instead.

GCC (Optional)

If you need GCC for compatibility with specific projects or for GCC-specific extensions:

sh
pkg install gcc13

GCC installs as gcc13 and g++13 to avoid conflicting with the base Clang:

sh
gcc13 --version g++13 --version

To use GCC for a specific project:

sh
export CC=gcc13 export CXX=g++13 gmake

Debugging Tools

sh
pkg install gdb lldb valgrind

FreeBSD's base system includes lldb. The packaged version may be newer. gdb is useful for projects that generate GDB-specific debug info.

Git

Install Git:

sh
pkg install git

Configure it:

sh
git config --global user.name "Your Name" git config --global user.email "you@example.com" git config --global core.editor nvim git config --global init.defaultBranch main git config --global pull.rebase true

Generate an SSH key for GitHub/GitLab:

sh
ssh-keygen -t ed25519 -C "you@example.com" cat ~/.ssh/id_ed25519.pub

Add the public key to your Git hosting provider.

Install additional Git tools:

sh
pkg install git-delta gh

git-delta provides better diff output. gh is the GitHub CLI.

Configure delta as the Git diff pager:

sh
git config --global core.pager delta git config --global interactive.diffFilter "delta --color-only" git config --global delta.navigate true git config --global merge.conflictstyle diff3

Python

FreeBSD packages Python by version. Install the version you need:

sh
pkg install python311 py311-pip py311-virtualenv

Create a symlink if you want python3 to point to your preferred version:

sh
ls -la /usr/local/bin/python3*

The package usually creates the python3 symlink automatically. If not:

sh
ln -sf /usr/local/bin/python3.11 /usr/local/bin/python3

Set up a virtual environment for a project:

sh
mkdir -p ~/projects/myapp cd ~/projects/myapp python3 -m venv venv source venv/bin/activate pip install -r requirements.txt

For data science and scientific computing:

sh
pkg install py311-numpy py311-pandas py311-matplotlib py311-scipy

Installing scientific libraries from pkg is faster than pip because they come pre-compiled with optimized BLAS/LAPACK on FreeBSD.

pyenv Alternative

If you need multiple Python versions side by side:

sh
pkg install pyenv

Add to your shell profile:

sh
export PYENV_ROOT="$HOME/.pyenv" export PATH="$PYENV_ROOT/bin:$PATH" eval "$(pyenv init -)"
sh
pyenv install 3.12.0 pyenv install 3.11.7 pyenv global 3.11.7 pyenv local 3.12.0 # per-project version

Rust

Install Rust via rustup (the official installer):

sh
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

Follow the prompts and accept the defaults. Then load the environment:

sh
source ~/.cargo/env

Verify:

sh
rustc --version cargo --version

Add common Rust development tools:

sh
rustup component add rustfmt clippy rust-analyzer

rust-analyzer provides IDE support (LSP) for Neovim and VS Code.

Create and build a test project:

sh
cargo new hello-world cd hello-world cargo build cargo run

Alternatively, install Rust from packages (simpler but less flexible):

sh
pkg install rust

The package version may lag behind rustup by a few releases.

Go

Install Go:

sh
pkg install go

Set up the Go workspace. Add to your shell profile:

sh
export GOPATH=$HOME/go export PATH=$PATH:$GOPATH/bin

Verify:

sh
go version

Create and run a test project:

sh
mkdir -p ~/go/src/hello vi ~/go/src/hello/main.go
go
package main import "fmt" func main() { fmt.Println("Hello from FreeBSD") }
sh
cd ~/go/src/hello go run main.go go build -o hello

Install common Go tools:

sh
go install golang.org/x/tools/gopls@latest go install github.com/go-delve/delve/cmd/dlv@latest

gopls is the Go language server for editor integration. dlv is the Go debugger.

Node.js

Install Node.js:

sh
pkg install node20 npm-node20

Verify:

sh
node --version npm --version

For managing multiple Node.js versions, use nvm:

sh
pkg install nvm

Add to your shell profile:

sh
export NVM_DIR="$HOME/.nvm" [ -s "/usr/local/share/nvm/nvm.sh" ] && . "/usr/local/share/nvm/nvm.sh"
sh
nvm install 20 nvm install 22 nvm use 20

Install Yarn (optional):

sh
npm install -g yarn

Editors

Neovim

Install Neovim:

sh
pkg install neovim

Create the configuration directory:

sh
mkdir -p ~/.config/nvim vi ~/.config/nvim/init.lua

A minimal configuration with LSP support:

lua
-- Basic settings vim.opt.number = true vim.opt.relativenumber = true vim.opt.tabstop = 4 vim.opt.shiftwidth = 4 vim.opt.expandtab = true vim.opt.smartindent = true vim.opt.termguicolors = true vim.opt.signcolumn = "yes" vim.opt.clipboard = "unnamedplus" -- Leader key vim.g.mapleader = " " -- Bootstrap lazy.nvim plugin manager local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim" if not vim.loop.fs_stat(lazypath) then vim.fn.system({ "git", "clone", "--filter=blob:none", "https://github.com/folke/lazy.nvim.git", "--branch=stable", lazypath, }) end vim.opt.rtp:prepend(lazypath) require("lazy").setup({ -- LSP { "neovim/nvim-lspconfig" }, { "hrsh7th/nvim-cmp" }, { "hrsh7th/cmp-nvim-lsp" }, -- Telescope (fuzzy finder) { "nvim-telescope/telescope.nvim", dependencies = { "nvim-lua/plenary.nvim" } }, -- Treesitter (syntax highlighting) { "nvim-treesitter/nvim-treesitter", build = ":TSUpdate" }, -- File tree { "nvim-tree/nvim-tree.lua" }, -- Git integration { "lewis6991/gitsigns.nvim" }, -- Status line { "nvim-lualine/lualine.nvim" }, })

Install language servers for your preferred languages. They work with Neovim's built-in LSP client:

sh
# Python pkg install py311-python-lsp-server # Go (already installed gopls above) # Rust (rust-analyzer installed via rustup above) # TypeScript/JavaScript npm install -g typescript-language-server typescript # Lua pkg install lua-language-server

VS Code (code-oss)

VS Code is available on FreeBSD as the open-source build:

sh
pkg install vscode

Launch it:

sh
code-oss

Install extensions for your languages from the command line:

sh
code-oss --install-extension rust-lang.rust-analyzer code-oss --install-extension golang.go code-oss --install-extension ms-python.python

Note: VS Code on FreeBSD is the OSS build and may not support all Marketplace extensions. The core functionality and major language extensions work.

Other Editors

sh
# Vim (traditional) pkg install vim # Emacs pkg install emacs-nox # terminal only pkg install emacs # with GUI # Helix (Rust-based modal editor with built-in LSP) pkg install helix

tmux Workflow

tmux is essential for server-based development. It lets you maintain persistent terminal sessions, split panes, and organize work into named windows.

sh
pkg install tmux

Create a configuration:

sh
vi ~/.tmux.conf
shell
# Use Ctrl-a as prefix (more ergonomic than Ctrl-b) unbind C-b set -g prefix C-a bind C-a send-prefix # Enable mouse set -g mouse on # Start window numbering at 1 set -g base-index 1 setw -g pane-base-index 1 # Better splits bind | split-window -h -c "#{pane_current_path}" bind - split-window -v -c "#{pane_current_path}" # Vi mode for copy setw -g mode-keys vi # Increase scrollback set -g history-limit 50000 # Reduce escape delay (important for Neovim) set -sg escape-time 10 # True color support set -g default-terminal "tmux-256color" set -ag terminal-overrides ",xterm-256color:RGB" # Status bar set -g status-style "bg=#1a1a1a,fg=#cccccc" set -g status-left "#[fg=green]#S " set -g status-right "#[fg=yellow]%H:%M #[fg=green]%Y-%m-%d"

A typical development workflow:

sh
# Create a named session for a project tmux new-session -s myproject # Split into editor and terminal panes # Ctrl-a | for vertical split # Ctrl-a - for horizontal split # Create separate windows for different tasks # Ctrl-a c for new window # Ctrl-a , to rename window

Container Alternatives with Jails

FreeBSD does not run Docker. The native alternative is jails, which provide OS-level virtualization with less overhead than containers.

For development environments, jails let you isolate dependencies per project:

sh
# Install a jail manager pkg install bastille sysrc bastille_enable="YES" service bastille start

Create a development jail:

sh
bastille bootstrap 14.2-RELEASE bastille create devenv 14.2-RELEASE 10.0.0.100

Enter the jail and install project-specific dependencies:

sh
bastille console devenv pkg install python311 postgresql16-server redis

Mount your source code into the jail:

sh
bastille mount devenv /home/user/projects /mnt/projects nullfs rw

This keeps your host system clean while giving each project an isolated environment with its own package set.

For Docker Compose-like orchestration, look at pot (another jail manager) or write shell scripts that manage multiple Bastille jails.

FreeBSD-Specific Development Tips

man Pages

FreeBSD has excellent man pages. Use them:

sh
man socket # BSD sockets API man kqueue # Event notification (FreeBSD's epoll equivalent) man jail # Jail system calls man capsicum # Capability-based security man dtrace # Dynamic tracing

Building FreeBSD Ports

If you maintain or contribute to FreeBSD ports:

sh
pkg install portlint porttools poudriere

Test a port build:

sh
cd /usr/ports/category/portname make stage make check-plist portlint -AC

Kernel Development

If you work on the FreeBSD kernel:

sh
# Fetch the source tree git clone https://git.freebsd.org/src.git /usr/src # Build the kernel cd /usr/src make -j$(sysctl -n hw.ncpu) buildkernel KERNCONF=GENERIC make installkernel KERNCONF=GENERIC

DTrace for Debugging

FreeBSD includes DTrace in the base system. Load the kernel module:

sh
kldload dtraceall

Trace system calls for a process:

sh
dtrace -n 'syscall:::entry /pid == $target/ { @[probefunc] = count(); }' -p $(pgrep myapp)

Shell Setup

Install and configure a modern shell:

sh
pkg install zsh zsh-autosuggestions zsh-syntax-highlighting chsh -s /usr/local/bin/zsh

Create a basic .zshrc:

sh
vi ~/.zshrc
sh
# History HISTSIZE=50000 SAVEHIST=50000 HISTFILE=~/.zsh_history setopt SHARE_HISTORY setopt HIST_IGNORE_DUPS # Prompt PROMPT='%F{green}%n@%m%f:%F{blue}%~%f$ ' # Aliases alias ll='ls -la' alias gs='git status' alias gd='git diff' alias gl='git log --oneline -20' # Paths export PATH="$HOME/.cargo/bin:$GOPATH/bin:$HOME/.local/bin:$PATH" # Plugins source /usr/local/share/zsh-autosuggestions/zsh-autosuggestions.zsh source /usr/local/share/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh

Troubleshooting

"gmake: command not found" when building a project:

Install GNU make:

sh
pkg install gmake

Some projects assume make is GNU make. Create an alias if needed:

sh
alias make=gmake

Compilation fails with "linux/xxx.h: No such file or directory":

The project uses Linux-specific headers. Check if the project has a FreeBSD port (pkg search portname) which includes the necessary patches. If building from source, you may need to port Linux-specific system calls to their FreeBSD equivalents (epoll to kqueue, etc.).

Node.js native modules fail to build:

Install build dependencies:

sh
pkg install python311 gmake gcc13

Set the compiler:

sh
export CXX=c++ export CC=cc npm install

Rust project fails with linker errors:

FreeBSD uses lld (LLVM linker) by default. Some Rust crates expect GNU ld. Install it:

sh
pkg install binutils

And add to your project's .cargo/config.toml:

toml
[target.x86_64-unknown-freebsd] linker = "cc"

VS Code remote SSH does not work:

The official VS Code Remote SSH extension does not support FreeBSD. Use the OSS build installed directly on FreeBSD, or use Neovim with a remote plugin.

FAQ

Is FreeBSD a good development platform?

Yes, for systems programming, server-side development, and anything involving BSD sockets, ZFS, jails, or network stacks. The toolchain is solid. For web frontend development, it works but some npm packages with native modules may need extra attention.

Can I run Docker on FreeBSD?

No, Docker requires the Linux kernel. FreeBSD alternatives are jails (native), Bastille (jail manager), and bhyve (full VM if you need Linux compatibility). You can run a Linux VM under bhyve and run Docker inside it if absolutely needed.

How do I keep development tools updated?

Run pkg update && pkg upgrade regularly. For tools installed via language-specific managers (rustup, pip, npm), update them separately:

sh
rustup update pip install --upgrade pip npm update -g

Does FreeBSD support VS Code Remote Development?

The official Microsoft VS Code Remote SSH extension does not support FreeBSD as a remote target. Alternatives: install VS Code directly on FreeBSD, use Neovim with remote editing, or use the code-server web-based VS Code which does run on FreeBSD.

How do I cross-compile for Linux from FreeBSD?

Install the Linux cross-compilation toolchain. For Rust, add the Linux target: rustup target add x86_64-unknown-linux-gnu and install the Linux linker. For C/C++, use a cross-compiler like x86_64-linux-gnu-gcc from packages. Cross-compilation is well supported for Go out of the box: GOOS=linux GOARCH=amd64 go build.

Where should I put my projects?

/home/username/projects/ is standard. On ZFS, consider creating a dedicated dataset: zfs create zroot/usr/home/username/projects for separate snapshot and compression policies.

Get more FreeBSD guides

Weekly tutorials, security advisories, and package updates. No spam.