My 2025 Development Setup: Tools, Configs, and Workflow
Jan 20, 2025 · 7 min · Developer Tools , Productivity , Setup , Workflow
My 2025 Development Setup: Tools, Configs, and Workflow
Introduction
Starting 2025 with a fresh development environment setup. After years of accumulating tools and configs, I decided to document everything in one place—both for my future self and anyone looking to optimize their workflow. This is the foundation I’m building on for the year ahead.
Hardware
Main Machine
System: Framework Laptop 13 (AMD Ryzen 7040 Series)
RAM: 64GB DDR5
Storage: 2TB NVMe SSD
Display: 2256x1504 @ 60Hz
OS: Arch Linux (btw)
Why Framework?
- Fully repairable and upgradeable
- Excellent Linux support
- Sustainable hardware philosophy
- Modular ports (swap USB-C, HDMI, etc.)
Peripherals
- Keyboard: ZSA Moonlander (Ergonomic split keyboard)
- Mouse: Logitech MX Master 3S
- Monitor: LG 32” 4K IPS (for when I dock)
- Webcam: Logitech C920 HD Pro
- Microphone: Blue Yeti (for occasional screencasts)
Operating System & Window Manager
Arch Linux + Hyprland
bash
# Display server
Wayland
# Window Manager
Hyprland (tiling, animations, eye candy)
# Terminal
Alacritty (GPU-accelerated)
# Shell
Zsh + Starship prompt
# Application Launcher
Rofi (Wayland fork)
# Status Bar
Waybar
# Notification Daemon
MakoWhy Hyprland?
Dynamic tiling with smooth animations. Best of both worlds:
ini
# ~/.config/hypr/hyprland.conf
# Performance
decoration {
rounding = 10
blur {
enabled = true
size = 3
passes = 1
}
drop_shadow = yes
shadow_range = 4
}
animations {
enabled = yes
bezier = myBezier, 0.05, 0.9, 0.1, 1.05
animation = windows, 1, 7, myBezier
animation = windowsOut, 1, 7, default, popin 80%
animation = fade, 1, 7, default
animation = workspaces, 1, 6, default
}
# Keybinds
bind = SUPER, Return, exec, alacritty
bind = SUPER, Q, killactive
bind = SUPER, M, exit
bind = SUPER, V, togglefloating
bind = SUPER, P, exec, rofi -show drun
# Move focus
bind = SUPER, h, movefocus, l
bind = SUPER, l, movefocus, r
bind = SUPER, k, movefocus, u
bind = SUPER, j, movefocus, d
# Switch workspaces
bind = SUPER, 1, workspace, 1
bind = SUPER, 2, workspace, 2
# ... etcTerminal Setup
Alacritty Config
yaml
# ~/.config/alacritty/alacritty.yml
window:
padding:
x: 10
y: 10
opacity: 0.95
font:
normal:
family: JetBrainsMono Nerd Font
style: Regular
bold:
family: JetBrainsMono Nerd Font
style: Bold
size: 12.0
colors:
primary:
background: '#1e1e2e'
foreground: '#cdd6f4'
normal:
black: '#45475a'
red: '#f38ba8'
green: '#a6e3a1'
yellow: '#f9e2af'
blue: '#89b4fa'
magenta: '#f5c2e7'
cyan: '#94e2d5'
white: '#bac2de'
cursor:
style:
shape: Block
blinking: OnZsh + Starship
bash
# ~/.zshrc
# History
HISTFILE=~/.zsh_history
HISTSIZE=10000
SAVEHIST=10000
setopt appendhistory
setopt sharehistory
setopt incappendhistory
# Plugins via zinit
source ~/.zinit/bin/zinit.zsh
zinit light zsh-users/zsh-autosuggestions
zinit light zsh-users/zsh-syntax-highlighting
zinit light zsh-users/zsh-completions
# Starship prompt
eval "$(starship init zsh)"
# Aliases
alias ls='exa --icons'
alias ll='exa -la --icons'
alias cat='bat'
alias find='fd'
alias grep='rg'
alias vim='nvim'
alias lg='lazygit'
# Functions
mkcd() {
mkdir -p "$1" && cd "$1"
}
extract() {
if [ -f $1 ]; then
case $1 in
*.tar.bz2) tar xjf $1 ;;
*.tar.gz) tar xzf $1 ;;
*.bz2) bunzip2 $1 ;;
*.rar) unrar x $1 ;;
*.gz) gunzip $1 ;;
*.tar) tar xf $1 ;;
*.tbz2) tar xjf $1 ;;
*.tgz) tar xzf $1 ;;
*.zip) unzip $1 ;;
*.Z) uncompress $1 ;;
*.7z) 7z x $1 ;;
*) echo "'$1' cannot be extracted" ;;
esac
else
echo "'$1' is not a valid file"
fi
}
# Development environments
export EDITOR='nvim'
export VISUAL='nvim'
export PAGER='bat'
# Path additions
export PATH="$HOME/.local/bin:$PATH"
export PATH="$HOME/.cargo/bin:$PATH"Starship Config
toml
# ~/.config/starship.toml
[character]
success_symbol = "[➜](bold green)"
error_symbol = "[✗](bold red)"
[directory]
truncation_length = 3
truncate_to_repo = true
format = "[$path]($style)[$read_only]($read_only_style) "
[git_branch]
symbol = " "
format = "on [$symbol$branch]($style) "
[git_status]
format = '([\[$all_status$ahead_behind\]]($style) )'
[rust]
symbol = " "
format = "via [$symbol$version]($style) "
[nodejs]
symbol = " "
format = "via [$symbol$version]($style) "
[python]
symbol = " "
format = "via [$symbol$version]($style) "
[cmd_duration]
min_time = 500
format = "took [$duration]($style) "Development Tools
Code Editor: Neovim
lua
-- ~/.config/nvim/init.lua
-- Bootstrap lazy.nvim
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)
-- Leader key
vim.g.mapleader = " "
-- Plugins
require("lazy").setup({
-- Theme
{
"catppuccin/nvim",
name = "catppuccin",
config = function()
vim.cmd.colorscheme("catppuccin-mocha")
end
},
-- LSP
{
"neovim/nvim-lspconfig",
dependencies = {
"williamboman/mason.nvim",
"williamboman/mason-lspconfig.nvim",
},
},
-- Autocomplete
{
"hrsh7th/nvim-cmp",
dependencies = {
"hrsh7th/cmp-nvim-lsp",
"hrsh7th/cmp-buffer",
"hrsh7th/cmp-path",
"L3MON4D3/LuaSnip",
},
},
-- Treesitter
{
"nvim-treesitter/nvim-treesitter",
build = ":TSUpdate",
},
-- Telescope
{
"nvim-telescope/telescope.nvim",
dependencies = { "nvim-lua/plenary.nvim" },
},
-- File explorer
{
"nvim-tree/nvim-tree.lua",
dependencies = { "nvim-tree/nvim-web-devicons" },
},
-- Git integration
{ "lewis6991/gitsigns.nvim" },
{ "tpope/vim-fugitive" },
-- Status line
{ "nvim-lualine/lualine.nvim" },
-- Rust tools
{ "simrat39/rust-tools.nvim" },
-- Copilot
{ "github/copilot.vim" },
})
-- Basic settings
vim.opt.number = true
vim.opt.relativenumber = true
vim.opt.expandtab = true
vim.opt.shiftwidth = 4
vim.opt.tabstop = 4
vim.opt.smartindent = true
vim.opt.wrap = false
vim.opt.swapfile = false
vim.opt.backup = false
vim.opt.undofile = true
vim.opt.hlsearch = false
vim.opt.incsearch = true
vim.opt.termguicolors = true
vim.opt.scrolloff = 8
vim.opt.signcolumn = "yes"
vim.opt.updatetime = 50
-- Keymaps
vim.keymap.set("n", "<leader>pv", vim.cmd.Ex)
vim.keymap.set("n", "<leader>ff", "<cmd>Telescope find_files<cr>")
vim.keymap.set("n", "<leader>fg", "<cmd>Telescope live_grep<cr>")
vim.keymap.set("n", "<leader>e", "<cmd>NvimTreeToggle<cr>")Version Control: Git
bash
# ~/.gitconfig
[user]
name = mxnish
email = your-email@example.com
signingkey = YOUR_GPG_KEY
[commit]
gpgsign = true
[core]
editor = nvim
pager = delta
[interactive]
diffFilter = delta --color-only
[delta]
navigate = true
light = false
side-by-side = true
line-numbers = true
[merge]
conflictstyle = diff3
[diff]
colorMoved = default
[alias]
st = status
co = checkout
br = branch
ci = commit
unstage = reset HEAD --
last = log -1 HEAD
visual = log --graph --oneline --all --decorate
amend = commit --amend --no-editLanguages & Runtimes
bash
# Rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
rustup component add rust-analyzer rustfmt clippy
# Node.js (via fnm)
curl -fsSL https://fnm.vercel.app/install | bash
fnm install --lts
# Python (via pyenv)
curl https://pyenv.run | bash
pyenv install 3.12.0
pyenv global 3.12.0
# Go
sudo pacman -S go
# Bun (faster npm alternative)
curl -fsSL https://bun.sh/install | bashProductivity Tools
Task Management
bash
# Using taskwarrior
sudo pacman -S task
# Add tasks
task add "Fix memory leak in DedCore" project:dedcore priority:H
task add "Write blog post about Rust" project:blog
# List tasks
task list
# Complete task
task 1 doneNote Taking: Obsidian
- Store notes in
~/Documents/obsidian/ - Sync via Git (private repo)
- Daily notes for journaling
- Zettelkasten method for knowledge management
Time Tracking: Timewarrior
bash
# Start tracking
timew start "Working on DedCore"
# Stop
timew stop
# Summary
timew summary :weekBrowser Setup: Firefox
Extensions
- uBlock Origin: Ad blocking
- Bitwarden: Password manager
- Dark Reader: Dark mode for websites
- Vimium: Vim keybindings for browsing
- Refined GitHub: Better GitHub UI
- Wappalyzer: Detect tech stacks
Firefox Config
about:config tweaks:
privacy.resistFingerprinting = true
network.http.referer.XOriginPolicy = 2
browser.safebrowsing.malware.enabled = true
browser.safebrowsing.phishing.enabled = true
Backup Strategy
Automated Backups
bash
#!/bin/bash
# ~/scripts/backup.sh
# Backup important configs
BACKUP_DIR="$HOME/Backups/$(date +%Y-%m-%d)"
mkdir -p "$BACKUP_DIR"
# Configs
cp -r ~/.config/nvim "$BACKUP_DIR/"
cp -r ~/.config/hypr "$BACKUP_DIR/"
cp ~/.zshrc "$BACKUP_DIR/"
cp ~/.gitconfig "$BACKUP_DIR/"
# Code projects
rsync -av --progress ~/Projects/ "$BACKUP_DIR/Projects/"
# Upload to cloud
rclone sync "$BACKUP_DIR" remote:backups/
echo "Backup complete: $BACKUP_DIR"Automated via systemd timer to run daily.
Dotfiles Management
Everything version controlled:
bash
# Using GNU Stow
cd ~/dotfiles
stow nvim
stow zsh
stow hypr
stow gitPublic repo: github.com/mxnish/dotfiles (sanitized)
What’s Next
This setup will evolve throughout 2025 as I:
- Build Rust projects (DedCore, RustyTasks)
- Explore Solana development (Need to add Solana CLI tools)
- Contribute to open source (Rust, Clippy, etc.)
- Write technical blog posts (This workflow makes it easy)
The goal: maximum productivity with minimal friction.
Want to see my full dotfiles? Check out github.com/mxnish/dotfiles
Edit this page on GitHub Last updated: 1/9/2026, 3:41:23 AM
Contributing to Rust Clippy: Fixing the useless_conversion Lint Building Jam: A Modern JavaScript Toolchain from Scratch