Commands Reference

This guide provides practical examples and explanations for bspc, the command-line tool used to control bspwm. Each command includes real-world use cases to help you understand when and why to use it.

Understanding bspc

bspc (Binary Space Partitioning Client) is how you communicate with bspwm. Every action—from moving windows to changing settings—goes through bspc. This design follows the UNIX philosophy: bspwm handles window management, while external tools (like sxhkd for keybindings) handle input.

The general syntax is:

bspc DOMAIN [SELECTOR] COMMAND [ARGUMENTS]

Domains are the types of objects you can control: - node - Individual windows and their containers - desktop - Virtual workspaces - monitor - Physical displays - query - Get information about the current state - wm - Window manager operations - rule - Automatic window placement rules - config - Configuration settings


Node Commands

Nodes are containers in bspwm's binary tree. Each window lives in a leaf node. Understanding nodes is key to mastering bspwm.

Focusing Windows

Focus a window in a direction:

# Focus the window to the west (left)
bspc node -f west

# Focus the window to the east (right)
bspc node -f east

# Focus up or down
bspc node -f north
bspc node -f south

These commands are spatial—they find the nearest window in that direction, making navigation intuitive.

Cycle through windows:

# Focus the next window in the current desktop
bspc node -f next.local

# Focus the previous window
bspc node -f prev.local

The .local modifier restricts the selection to the current desktop. Without it, next and prev would cycle through all windows across all desktops.

Focus the last focused window:

bspc node -f last

This is incredibly useful for toggling between two windows you're actively working with.

Focus the biggest window:

bspc node -f biggest.local

Helpful when you have many small windows and want to jump to the main one.

Moving Windows

Swap windows:

# Swap the focused window with the one to the east
bspc node -s east

# Swap with any direction
bspc node -s north
bspc node -s south
bspc node -s west

Swapping exchanges the positions of two windows in the tree without changing their sizes.

Send a window to another desktop:

# Send focused window to desktop 3
bspc node -d '^3'

# Send to a named desktop
bspc node -d 'Web'

# Send and follow (focus the target desktop)
bspc node -d '^3' --follow

The ^3 syntax means "the 3rd desktop". You can also use desktop names directly.

Send a window to another monitor:

# Send to the next monitor
bspc node -m next

# Send to a specific monitor by name
bspc node -m HDMI-1

# Send to the monitor in a direction
bspc node -m west

Changing Window State

bspwm has four window states, each serving different purposes:

Tiled (default): Windows are arranged automatically by the binary tree. Size and position are determined by split ratios.

bspc node -t tiled

Pseudo-tiled: The window occupies a tiling slot but maintains its preferred size, centered within that slot. Perfect for windows that look bad when stretched (like some dialogs).

bspc node -t pseudo_tiled

Floating: The window can be moved and resized freely, like in a traditional stacking window manager. It floats above tiled windows but is still part of the tree.

bspc node -t floating

Fullscreen: The window fills the entire monitor, covering the bar and other windows. No borders are shown.

bspc node -t fullscreen

Toggle between states:

The ~ prefix toggles—if the window is already in that state, it returns to its previous state:

# Toggle fullscreen (press again to restore)
bspc node -t ~fullscreen

# Toggle floating
bspc node -t ~floating

Window Flags

Flags modify window behavior without changing their state:

Hidden: The window becomes invisible but remains in the tree. Useful for scratchpad terminals.

# Hide the focused window
bspc node -g hidden=on

# Show a hidden window (you need its ID)
bspc node 0x01800003 -g hidden=off

Sticky: The window follows you to every desktop on its monitor. Perfect for music players or chat windows.

bspc node -g sticky=on

Locked: The window can't be closed with bspc node -c. Protects important windows from accidental closure.

bspc node -g locked=on

Private: The window tries to maintain its tiling position. Other windows won't push it around when inserted.

bspc node -g private=on

Closing and Killing Windows

# Close the focused window gracefully (sends WM_DELETE_WINDOW)
bspc node -c

# Kill the window forcefully (for unresponsive applications)
bspc node -k

Always prefer -c (close) over -k (kill). Close gives applications a chance to save data and clean up.

Resizing Windows

Resize by moving edges:

# Expand the right edge by 20 pixels
bspc node -z right 20 0

# Shrink the right edge by 20 pixels
bspc node -z right -20 0

# Expand downward
bspc node -z bottom 0 20

# Expand in a corner direction
bspc node -z bottom_right 20 20

The syntax is bspc node -z HANDLE dx dy where: - HANDLE is which edge to move: top, bottom, left, right, or corners like top_left - dx is horizontal movement (positive = right) - dy is vertical movement (positive = down)

Set exact split ratio:

# Set the split ratio to 0.7 (70% for first child)
bspc node -r 0.7

# Adjust ratio relatively
bspc node -r +0.1
bspc node -r -0.1

Balance all windows equally:

bspc node @/ -B

The @/ selector means "the root of the tree". This makes all windows on the desktop occupy equal space.

Equalize split ratios:

bspc node @/ -E

Resets all split ratios to 0.5 (50/50 splits).

Rotating and Flipping the Layout

Rotate the tree:

# Rotate 90 degrees clockwise
bspc node @/ -R 90

# Rotate counter-clockwise
bspc node @/ -R 270

# Rotate 180 degrees
bspc node @/ -R 180

Flip the tree:

# Flip horizontally (mirror left/right)
bspc node @/ -F horizontal

# Flip vertically (mirror top/bottom)
bspc node @/ -F vertical

Pre-selection (Manual Insertion)

Pre-selection lets you choose exactly where the next window will appear:

# Pre-select to split the focused window to the west
bspc node -p west

# Pre-select with a specific ratio
bspc node -p west -o 0.3

# Cancel pre-selection
bspc node -p cancel

When you run a pre-selection command, a colored area appears showing where the next window will go. This is "manual insertion mode"—the opposite of bspwm's default automatic placement.


Desktop Commands

Desktops are virtual workspaces. Each monitor has one or more desktops, and each desktop contains a binary tree of windows.

Focusing Desktops

# Focus desktop by index
bspc desktop -f '^1'   # First desktop
bspc desktop -f '^3'   # Third desktop

# Focus by name
bspc desktop -f 'Web'
bspc desktop -f 'Code'

# Cycle through desktops
bspc desktop -f next
bspc desktop -f prev

# Focus last desktop
bspc desktop -f last

# Focus next occupied desktop (skip empty ones)
bspc desktop -f next.occupied

Managing Desktops

Rename a desktop:

bspc desktop -n 'NewName'
bspc desktop '^2' -n 'Web'

Change layout:

# Switch to monocle layout (one window visible at a time)
bspc desktop -l monocle

# Switch back to tiled layout
bspc desktop -l tiled

# Cycle between layouts
bspc desktop -l next

Monocle layout shows only the focused window, maximized. Other windows are hidden behind it. Perfect for focusing on one task.

Remove an empty desktop:

bspc desktop -r

This only works if the desktop has no windows.

Reordering Desktops

# Swap desktop positions
bspc desktop -s next
bspc desktop -s prev

# Bubble desktop position (move it through the list)
bspc desktop -b next
bspc desktop -b prev

Monitor Commands

Monitors represent physical displays. Each monitor has its own set of desktops.

Focusing Monitors

# Focus monitor by direction
bspc monitor -f west
bspc monitor -f east

# Focus by name
bspc monitor -f 'HDMI-1'
bspc monitor -f 'eDP-1'

# Cycle monitors
bspc monitor -f next
bspc monitor -f prev

# Focus primary monitor
bspc monitor -f primary

Configuring Desktops on Monitors

# Set desktops for a monitor (replaces existing)
bspc monitor HDMI-1 -d I II III IV V

# Add desktops to a monitor
bspc monitor -a VI VII

# Reorder desktops
bspc monitor -o I II III IV V

Query Commands

Query commands retrieve information about bspwm's state. Essential for scripting.

List Objects

# List all window IDs
bspc query -N

# List windows on current desktop
bspc query -N -d focused

# List desktop names
bspc query -D --names

# List monitor names
bspc query -M --names

Get Tree Structure

# Get JSON tree of focused desktop
bspc query -T -d focused

# Get full state as JSON
bspc query -T

Check Focused Objects

# Get focused window ID
bspc query -N -n focused

# Get focused desktop name
bspc query -D -d focused --names

# Get focused monitor name
bspc query -M -m focused --names

Count Windows

# Count windows on current desktop
bspc query -N -d focused | wc -l

# Count all windows
bspc query -N | wc -l

Config Commands

The config domain gets and sets bspwm settings dynamically—no restart needed.

Getting Values

# Get current border width
bspc config border_width

# Get window gap
bspc config window_gap

# Get focused border color
bspc config focused_border_color

Setting Values

# Set border width
bspc config border_width 2

# Set window gap
bspc config window_gap 10

# Set colors
bspc config focused_border_color '#ff0000'
bspc config normal_border_color '#444444'

Per-Desktop Settings

# Set gap only for desktop 1
bspc config -d '^1' window_gap 0

# Different padding per desktop
bspc config -d 'Coding' top_padding 0

See Settings Reference for all available options.


Rule Commands

Rules automatically configure windows based on their class or instance name.

Adding Rules

# Firefox always opens on desktop 2
bspc rule -a Firefox desktop='^2'

# Gimp floats
bspc rule -a Gimp state=floating

# Spotify on desktop 10, follows focus
bspc rule -a Spotify desktop='^10' follow=on

# Picture-in-picture always floats and stays on top
bspc rule -a '*:*:Picture-in-Picture' state=floating sticky=on layer=above

Listing and Removing Rules

# List all rules
bspc rule -l

# Remove a rule by class
bspc rule -r Firefox

# Remove all rules
bspc rule -r '*'

See Window Rules for comprehensive rule documentation.


WM Commands

Control the window manager itself.

# Quit bspwm
bspc quit

# Quit with a specific exit code
bspc quit 1

# Dump state to file (for restoring after restart)
bspc wm -d > /tmp/bspwm-state

# Load state from file
bspc wm -l /tmp/bspwm-state

# Adopt orphaned windows (after a crash/restart)
bspc wm -o

Practical Examples

Toggle a Scratchpad Terminal

#!/bin/bash
# scratchpad.sh - toggle a dropdown terminal

id=$(xdotool search --class scratchterm)
if [ -z "$id" ]; then
    # Terminal doesn't exist, create it
    alacritty --class scratchterm &
else
    # Toggle visibility
    bspc node "$id" -g hidden -f
fi

Move and Resize Floating Windows with Keyboard

# In sxhkdrc:

# Move floating window
super + {Left,Down,Up,Right}
    bspc node -v {-20 0, 0 20, 0 -20, 20 0}

# Resize floating window
super + alt + {Left,Down,Up,Right}
    bspc node -z {left -20 0, bottom 0 20, top 0 -20, right 20 0}

Smart Window Focusing

# Focus next window, wrapping to next desktop if needed
bspc node -f next.local || bspc desktop -f next

Cycle Through Window States

#!/bin/bash
# cycle-state.sh - cycle through tiled → floating → fullscreen

state=$(bspc query -T -n focused | jq -r '.client.state')
case $state in
    tiled) bspc node -t floating ;;
    floating) bspc node -t fullscreen ;;
    fullscreen) bspc node -t tiled ;;
esac

Swap Focused Window with Largest

#!/bin/bash
# swap-biggest.sh - swap focused window with the biggest one
bspc node -s biggest.local

Move Window to Next/Previous Desktop

# In sxhkdrc:
super + shift + {Left,Right}
    bspc node -d {prev,next}.local --follow

Close All Windows on Current Desktop

#!/bin/bash
# close-all.sh - close all windows on current desktop
for node in $(bspc query -N -d focused); do
    bspc node "$node" -c
done

Create a Master-Stack Layout

This script creates a layout where one window (the "master") takes up the left half, and remaining windows stack on the right:

#!/bin/bash
# master-stack.sh - create master-stack layout

# Balance first
bspc node @/ -B

# Get all windows
windows=($(bspc query -N -d focused -n .leaf))

if [ ${#windows[@]} -lt 2 ]; then
    exit 0
fi

# Rotate to ensure horizontal split at root
bspc node @/ -R 90

# Set master ratio (60% for master)
bspc node @/ -r 0.6

Dynamic Gap Adjustment

#!/bin/bash
# adjust-gaps.sh - increase/decrease gaps
# Usage: adjust-gaps.sh +5 or adjust-gaps.sh -5

current=$(bspc config window_gap)
new=$((current $1))

if [ $new -lt 0 ]; then
    new=0
fi

bspc config window_gap $new

In sxhkdrc:

super + {minus,equal}
    ~/.local/bin/adjust-gaps.sh {-5,+5}

Workspace Indicators for Status Bars

#!/bin/bash
# workspace-status.sh - output workspace info for lemonbar/polybar

bspc subscribe report | while read -r line; do
    output=""
    IFS=':'
    for item in $line; do
        name="${item#?}"
        case $item in
            O*) output+="%{F#ffffff}[$name]%{F-} " ;;  # Focused occupied
            F*) output+="%{F#ffffff}[$name]%{F-} " ;;  # Focused free
            U*) output+="%{F#ff0000}[$name]%{F-} " ;;  # Focused urgent
            o*) output+="%{F#888888} $name  %{F-}" ;;  # Unfocused occupied
            f*) output+="%{F#444444} $name  %{F-}" ;;  # Unfocused free
            u*) output+="%{F#ff0000} $name  %{F-}" ;;  # Unfocused urgent
        esac
    done
    echo "$output"
done

Workflow Tips

These tips come from daily bspwm usage and help you work more efficiently.

Organize Desktops by Task

Instead of numbering desktops, name them by function:

# In bspwmrc:
bspc monitor -d terminal web code mail media chat files misc sys

Then use rules to automatically place applications:

bspc rule -a Firefox desktop='web'
bspc rule -a Code desktop='code'
bspc rule -a thunderbird desktop='mail'
bspc rule -a Spotify desktop='media'
bspc rule -a Slack desktop='chat'

Use Receptacles for Consistent Layouts

Pre-create your layout before opening applications:

#!/bin/bash
# dev-layout.sh - create development layout

# Switch to code desktop
bspc desktop -f 'code'

# Clear existing windows (optional)
# for node in $(bspc query -N -d focused); do bspc node "$node" -c; done

# Create receptacles in desired layout
bspc node -i  # First slot (editor)
bspc node -p east -o 0.7  # Preselect for terminal area
bspc node -i  # Terminal slot
bspc node -p south  # Preselect for second terminal
bspc node -i  # Second terminal slot

# Now open applications - they fill receptacles in order
code &
sleep 0.5
alacritty &
sleep 0.3
alacritty &

Quick Desktop Overview

Use monocle mode with easy cycling for a "virtual desktop" feel:

# In sxhkdrc:

# Toggle monocle
super + m
    bspc desktop -l next

# When in monocle, cycle windows
super + {comma,period}
    bspc node -f {prev,next}.local

Emergency Fallback Keybindings

Always have a way to recover if something goes wrong:

# In sxhkdrc - recovery bindings:

# Force quit bspwm (use only if stuck)
super + alt + shift + q
    bspc quit 1

# Kill focused window forcefully
super + alt + shift + c
    bspc node -k

# Unhide all hidden windows
super + alt + shift + u
    for n in $(bspc query -N -n .hidden); do bspc node "$n" -g hidden=off; done

Efficient Window Navigation

The most efficient navigation combines direction-based and history-based movement:

# In sxhkdrc:

# Direction-based (vim-style)
super + {h,j,k,l}
    bspc node -f {west,south,north,east}

# History-based
super + {grave,Tab}
    bspc node -f {last,next.local}

# Jump to urgent window anywhere
super + u
    bspc node -f any.urgent

Save and Restore Layouts

For complex setups you use frequently:

#!/bin/bash
# save-layout.sh
bspc wm -d > ~/.config/bspwm/layouts/$(bspc query -D -d focused --names).json

#!/bin/bash  
# restore-layout.sh
layout_file=~/.config/bspwm/layouts/$(bspc query -D -d focused --names).json
if [ -f "$layout_file" ]; then
    bspc wm -l "$layout_file"
fi

Handle Transient Windows

Some applications (like file dialogs) should always float:

# In external_rules:
#!/bin/bash
wid=$1
class=$2
instance=$3

# Check if window is transient (dialog, popup)
transient=$(xprop -id "$wid" WM_TRANSIENT_FOR 2>/dev/null)
if [ -n "$transient" ] && [ "$transient" != "WM_TRANSIENT_FOR:  not found." ]; then
    echo "state=floating center=on"
fi