← All articles
PRODUCTIVITY Developer Productivity Systems: Tools and Workflows ... 2026-02-09 · 9 min read · productivity · dotfiles · automation

Developer Productivity Systems: Tools and Workflows That Actually Work

Productivity 2026-02-09 · 9 min read productivity dotfiles automation time-tracking developer-tools workflow

Developer Productivity Systems: Tools and Workflows That Actually Work

Most productivity advice is generic and vague. This guide is specifically about developer productivity -- the concrete tools, configurations, and workflows that eliminate friction from your daily work. Not philosophy, not time management theory. Just things you can set up today that will save you real time.

Dotfiles Management

Your shell configuration, editor settings, and tool configs are the foundation of your development environment. Managing them properly means you can set up a new machine in minutes, not hours.

Getting Started with Dotfiles

# Initialize a dotfiles repo
mkdir ~/dotfiles
cd ~/dotfiles
git init

# Move your config files here
mv ~/.zshrc ~/dotfiles/zshrc
mv ~/.gitconfig ~/dotfiles/gitconfig
mv ~/.config/starship.toml ~/dotfiles/starship.toml

# Create symlinks back
ln -sf ~/dotfiles/zshrc ~/.zshrc
ln -sf ~/dotfiles/gitconfig ~/.gitconfig
ln -sf ~/dotfiles/starship.toml ~/.config/starship.toml

Automated Setup Script

#!/bin/bash
# install.sh -- idempotent dotfiles installation

set -euo pipefail

DOTFILES="$HOME/dotfiles"

# Symlink dotfiles
link() {
  local src="$DOTFILES/$1"
  local dst="$2"
  mkdir -p "$(dirname "$dst")"

  if [ -L "$dst" ]; then
    rm "$dst"
  elif [ -f "$dst" ]; then
    mv "$dst" "$dst.backup"
    echo "Backed up existing $dst"
  fi

  ln -sf "$src" "$dst"
  echo "Linked $src -> $dst"
}

link "zshrc" "$HOME/.zshrc"
link "gitconfig" "$HOME/.gitconfig"
link "starship.toml" "$HOME/.config/starship.toml"
link "alacritty.toml" "$HOME/.config/alacritty/alacritty.toml"
link "tmux.conf" "$HOME/.tmux.conf"

# Install tools if missing
command -v starship >/dev/null || curl -sS https://starship.rs/install.sh | sh
command -v fzf >/dev/null || git clone --depth 1 https://github.com/junegunn/fzf.git ~/.fzf && ~/.fzf/install
command -v zoxide >/dev/null || curl -sSfL https://raw.githubusercontent.com/ajeetdsouza/zoxide/main/install.sh | sh
command -v eza >/dev/null || cargo install eza

echo "Dotfiles installation complete."

Essential Shell Configuration

# .zshrc -- the parts that actually matter

# History configuration (often overlooked, saves hours over time)
HISTSIZE=50000
SAVEHIST=50000
HISTFILE=~/.zsh_history
setopt SHARE_HISTORY          # Share history between sessions
setopt HIST_EXPIRE_DUPS_FIRST # Remove duplicates first when trimming
setopt HIST_IGNORE_DUPS       # Don't record duplicate commands
setopt HIST_FIND_NO_DUPS      # Don't show duplicates in search

# Modern replacements for classic tools
alias ls="eza --icons"
alias ll="eza -la --icons --git"
alias cat="bat"
alias find="fd"
alias grep="rg"
alias top="btop"
alias du="dust"
alias diff="delta"

# Zoxide -- smarter cd
eval "$(zoxide init zsh)"
# Usage: z project-name  (instead of cd ~/projects/my-long-project-name)

# fzf -- fuzzy finder for everything
export FZF_DEFAULT_COMMAND='fd --type f --hidden --follow --exclude .git'
export FZF_CTRL_T_COMMAND="$FZF_DEFAULT_COMMAND"
export FZF_ALT_C_COMMAND='fd --type d --hidden --follow --exclude .git'

# Quick project navigation
p() {
  local dir
  dir=$(fd --type d --max-depth 2 . ~/projects ~/work | fzf --preview 'eza -la {}')
  [ -n "$dir" ] && cd "$dir"
}

# Search command history with fzf
bindkey '^R' fzf-history-widget

Git Productivity

Git is the tool you use most. Small efficiency gains here compound enormously.

Git Aliases That Save Real Time

# ~/.gitconfig
[alias]
  s = status --short --branch
  co = checkout
  cb = checkout -b
  cm = commit -m
  ca = commit --amend --no-edit
  d = diff
  ds = diff --staged
  lg = log --graph --oneline --decorate -20
  lga = log --graph --oneline --decorate --all -20
  undo = reset HEAD~1 --mixed
  wip = !git add -A && git commit -m 'WIP'
  unwip = reset HEAD~1 --mixed
  sync = !git fetch --all --prune && git rebase origin/main
  cleanup = !git branch --merged | grep -v '\\*\\|main\\|master' | xargs -n 1 git branch -d

[pull]
  rebase = true

[push]
  autoSetupRemote = true

[rerere]
  enabled = true    # Remember conflict resolutions

[diff]
  algorithm = histogram
  colorMoved = default

[merge]
  conflictStyle = zdiff3

[core]
  pager = delta

[delta]
  navigate = true
  side-by-side = true
  line-numbers = true

Git Worktrees for Parallel Work

Instead of stashing or switching branches, use worktrees to have multiple branches checked out simultaneously:

# Create a worktree for a feature branch
git worktree add ../my-project-feature feature-branch

# Create a worktree for a bug fix
git worktree add ../my-project-hotfix hotfix-branch

# List worktrees
git worktree list

# Clean up when done
git worktree remove ../my-project-feature

This is invaluable when you need to quickly review a PR or fix a bug without losing your current working state.

Interactive Rebase with Autosquash

# Mark a commit as a fixup for an earlier commit
git commit --fixup=abc1234

# Later, automatically squash fixup commits
git rebase -i --autosquash main

# Enable autosquash by default
git config --global rebase.autoSquash true

Code Snippets and Templates

Typing the same patterns repeatedly is a waste of time. Build a snippet library.

VS Code Snippets

// .vscode/project.code-snippets
{
  "React Functional Component": {
    "prefix": "rfc",
    "body": [
      "interface ${1:Component}Props {",
      "  $2",
      "}",
      "",
      "export function ${1:Component}({ $3 }: ${1:Component}Props) {",
      "  return (",
      "    <div>",
      "      $0",
      "    </div>",
      "  );",
      "}"
    ],
    "description": "React Functional Component with TypeScript props"
  },
  "Express Route Handler": {
    "prefix": "handler",
    "body": [
      "export async function ${1:handler}(req: Request, res: Response) {",
      "  try {",
      "    $0",
      "    res.json({ success: true });",
      "  } catch (error) {",
      "    console.error('${1:handler} failed:', error);",
      "    res.status(500).json({ error: 'Internal server error' });",
      "  }",
      "}"
    ]
  },
  "Test Block": {
    "prefix": "desc",
    "body": [
      "describe('${1:subject}', () => {",
      "  it('should ${2:behavior}', () => {",
      "    $0",
      "  });",
      "});"
    ]
  }
}

File Templates with Scaffolding Scripts

#!/bin/bash
# scripts/new-component.sh -- scaffold a new React component

NAME=$1
DIR="src/components/$NAME"

if [ -z "$NAME" ]; then
  echo "Usage: new-component.sh ComponentName"
  exit 1
fi

mkdir -p "$DIR"

cat > "$DIR/$NAME.tsx" << EOF
interface ${NAME}Props {
  className?: string;
}

export function ${NAME}({ className }: ${NAME}Props) {
  return (
    <div className={className}>
      ${NAME}
    </div>
  );
}
EOF

cat > "$DIR/$NAME.test.tsx" << EOF
import { render, screen } from "@testing-library/react";
import { ${NAME} } from "./${NAME}";

describe("${NAME}", () => {
  it("renders without crashing", () => {
    render(<${NAME} />);
    expect(screen.getByText("${NAME}")).toBeInTheDocument();
  });
});
EOF

cat > "$DIR/index.ts" << EOF
export { ${NAME} } from "./${NAME}";
EOF

echo "Created component at $DIR"

Terminal Multiplexing with tmux

tmux lets you manage multiple terminal sessions, split panes, and persist sessions across disconnections.

Essential tmux Configuration

# ~/.tmux.conf
# Change prefix to Ctrl+A (easier to reach than Ctrl+B)
set -g prefix C-a
unbind C-b
bind C-a send-prefix

# Start windows and panes at 1 (not 0)
set -g base-index 1
setw -g pane-base-index 1

# Renumber windows when one is closed
set -g renumber-windows on

# Split panes with | and -
bind | split-window -h -c "#{pane_current_path}"
bind - split-window -v -c "#{pane_current_path}"

# Navigate panes with vim keys
bind h select-pane -L
bind j select-pane -D
bind k select-pane -U
bind l select-pane -R

# Resize panes with vim keys
bind -r H resize-pane -L 5
bind -r J resize-pane -D 5
bind -r K resize-pane -U 5
bind -r L resize-pane -R 5

# Mouse support
set -g mouse on

# Increase scrollback buffer
set -g history-limit 50000

# Fast escape time (for vim users)
set -sg escape-time 0

# True color support
set -g default-terminal "tmux-256color"
set -ag terminal-overrides ",xterm-256color:RGB"

tmux Session Management

# Create named sessions for different projects
tmux new-session -s web -d
tmux new-session -s api -d
tmux new-session -s infra -d

# Script to start a development session
#!/bin/bash
# dev-session.sh
SESSION="dev"

tmux new-session -d -s $SESSION -c ~/projects/my-app

# Editor window
tmux rename-window -t $SESSION:1 "editor"
tmux send-keys -t $SESSION:1 "nvim ." C-m

# Server window
tmux new-window -t $SESSION -n "server" -c ~/projects/my-app
tmux send-keys -t $SESSION:2 "bun run dev" C-m

# Git window
tmux new-window -t $SESSION -n "git" -c ~/projects/my-app

# Logs window (split into two panes)
tmux new-window -t $SESSION -n "logs" -c ~/projects/my-app
tmux split-window -h -t $SESSION:4
tmux send-keys -t $SESSION:4.1 "tail -f logs/app.log" C-m
tmux send-keys -t $SESSION:4.2 "tail -f logs/error.log" C-m

# Select the editor window
tmux select-window -t $SESSION:1

tmux attach -t $SESSION

Time Tracking for Developers

Tracking where your time goes reveals surprising patterns. Most developers overestimate coding time and underestimate context-switching costs.

Time Tracking Tools

Tool Approach Free? Best For
Toggl Track Manual timer Free tier Freelancers, billing
WakaTime Automatic (editor plugin) Free tier Understanding coding patterns
ActivityWatch Automatic (system-level) Free (OSS) Full computer usage tracking
Clockify Manual timer Free Teams
RescueTime Automatic (system-level) Free tier Identifying distractions

WakaTime Setup

WakaTime tracks time automatically based on which files you edit. Install the plugin for your editor and forget about it.

# Install WakaTime CLI
pip install wakatime

# VS Code: Install "WakaTime" extension
# Vim/Neovim: Install wakatime/vim-wakatime
# JetBrains: Install from marketplace

WakaTime's dashboard shows:

Automated Time Logging with Git

# git-hours -- estimate time from commit history
npx git-hours

# Simple script to track daily coding time from git
#!/bin/bash
# coding-time.sh -- how much did I code today?
echo "Commits today:"
git log --oneline --since="today" --author="$(git config user.name)"
echo ""
echo "Files changed:"
git diff --stat HEAD~$(git log --oneline --since="today" | wc -l) 2>/dev/null || echo "No changes"

Workspace Automation

Task Runners with Just

just is a modern alternative to make for running project-specific commands:

# justfile
default:
  @just --list

# Development
dev:
  bun run dev

# Testing
test:
  bun test

test-watch:
  bun test --watch

# Code quality
lint:
  bunx biome check .

format:
  bunx biome format --write .

check: lint test
  echo "All checks passed"

# Database
db-up:
  docker compose up -d postgres redis

db-migrate:
  bun run prisma migrate dev

db-reset:
  bun run prisma migrate reset

db-studio:
  bun run prisma studio

# Deployment
deploy-staging:
  git push origin main:staging

deploy-production:
  @echo "Are you sure? [y/N]" && read ans && [ $${ans:-N} = y ]
  git push origin main:production

# Utilities
clean:
  rm -rf node_modules dist .next .turbo

nuke: clean
  bun install

VS Code Workspace Settings

// .vscode/settings.json -- project-specific settings
{
  "editor.formatOnSave": true,
  "editor.defaultFormatter": "biomejs.biome",
  "editor.codeActionsOnSave": {
    "source.organizeImports.biome": "explicit"
  },
  "typescript.preferences.importModuleSpecifier": "non-relative",
  "search.exclude": {
    "**/node_modules": true,
    "**/dist": true,
    "**/.next": true,
    "**/coverage": true
  },
  "files.associations": {
    "*.css": "tailwindcss"
  }
}
// .vscode/extensions.json -- recommended extensions for the team
{
  "recommendations": [
    "biomejs.biome",
    "bradlc.vscode-tailwindcss",
    "prisma.prisma",
    "dbaeumer.vscode-eslint",
    "eamodio.gitlens",
    "wakatime.vscode-wakatime"
  ]
}

Focus and Deep Work Techniques

The Pomodoro Technique (Adapted for Developers)

Standard Pomodoro (25min work / 5min break) is too short for most coding tasks. A modified version works better:

# Simple CLI pomodoro timer
# Install: cargo install porsmo
porsmo pomodoro 50 10 30  # 50min work, 10min break, 30min long break

Notification Management

# macOS: Focus mode via CLI
# Create a "Coding" focus in System Settings, then:
shortcuts run "Turn On Coding Focus"

# Linux: Do Not Disturb via dunstctl
dunstctl set-paused true   # Pause notifications
dunstctl set-paused false  # Resume

Communication Batching

The most impactful productivity change isn't a tool -- it's checking Slack/email only at designated times instead of reactively. Configure your communication tools:

Building Your System

The key is to start small and iterate. Here's a prioritized adoption plan:

Week 1: Shell Efficiency

Week 2: Editor and Project Setup

Week 3: Automation and Tracking

Week 4: Review and Refine

Summary

Developer productivity isn't about working faster -- it's about removing friction. Every second spent waiting for a command, retyping a pattern, or setting up an environment is a second not spent solving problems. The tools and techniques here are all incremental improvements, but they compound. A developer who saves 30 minutes a day through better tooling saves over 120 hours a year. That's three full work weeks reclaimed for actual thinking and building.