What is config.h?

config.h is the configuration file for dwm. It is a C source file, but you do not need to know C to edit it. After every change, recompile and restart dwm:

cd ~/dwm
make
make install

Before making larger changes, create a backup:

cp config.h config.h.bak

To start, copy the template:

cp config.def.h config.h

Important: after a git pull, always compare your config.h with the updated config.def.h to catch new options:

diff config.def.h config.h

Do I Need to Know C?

No.

For basic customisation, you usually only change:

  • numbers (like borderpx = 1)

  • strings inside quotes (like "monospace:size=10")

  • color hex values (like "#222222")

  • key symbols (like XK_p, XK_Return)

You are not writing functions. You are not changing algorithms. You are only editing values.

If you can edit a .conf file, you can edit config.h.

Dependencies

dwm itself has no runtime dependencies beyond Xlib, but the default bindings expect two external programs to be installed:

  • dmenu — launched by Alt + p

  • st — launched by Alt + Shift + Return

Both are suckless projects and follow the same make && make install process. If either is missing, the binding fails silently — dwm will not crash.

Colors

Five color variables are defined near the top of config.h:

static const char col_gray1[] = "#222222";  /* bar background          */
static const char col_gray2[] = "#444444";  /* unfocused border        */
static const char col_gray3[] = "#bbbbbb";  /* normal text             */
static const char col_gray4[] = "#eeeeee";  /* selected text           */
static const char col_cyan[]  = "#005577";  /* focused border + bar bg */

To change a color, replace the hex value. The variable names are arbitrary. You may rename them, but every reference inside colors[] must be updated accordingly.

The colors[] table assigns those variables to states:

static const char *colors[][3] = {
    /*               fg         bg         border    */
    [SchemeNorm] = { col_gray3, col_gray1, col_gray2 }, /* unfocused */
    [SchemeSel]  = { col_gray4, col_cyan,  col_cyan  }, /* focused   */
};

SchemeNorm applies to unfocused windows and the bar. SchemeSel applies to the focused window and the selected dmenu entry.

Font

static const char *fonts[]    = { "monospace:size=10" };
static const char dmenufont[] = "monospace:size=10";

monospace is a generic fontconfig alias that resolves to whatever monospace font is installed on the system. It works out of the box without installing anything extra.

Replace the font name and size to taste. Both fonts[] and dmenufont should use the same value for consistency.

fonts[] accepts multiple entries. dwm tries each in order and falls back to the next if a glyph is missing. This is useful for mixing a text font with a symbol or emoji font:

static const char *fonts[] = {
    "Iosevka Term:size=11",
    "Noto Color Emoji:size=11"
};

Finding the Correct Font Name

The display name and the fontconfig name often differ. To find the exact name as fontconfig sees it:

fc-list | grep -i "fontname"

Some examples:

  • "JetBrains Mono NF" may be known as "JetBrainsMono Nerd Font Regular"

  • "Iosevka" may be known as "Iosevka Term"

Once you have the correct name:

static const char *fonts[]    = { "Iosevka Term:size=11:antialias=true" };
static const char dmenufont[] = "Iosevka Term:size=11:antialias=true";

Fonts on Slackware

Slackware users can find both fonts on SlackBuilds.org:

Iosevka-core (minimal subset, sufficient for dwm and st):
https://slackbuilds.org/repository/15.0/system/Iosevka-core/

Iosevka-core contains only the essential font files. If you only need Iosevka for dwm and st, use Iosevka-core instead of the full package.

On other distributions, look for packages named iosevka or fonts-iosevka in your package manager.

Border & Bar

static const unsigned int borderpx = 1;  /* border width in pixels */
static const int showbar            = 1; /* 1 = show bar, 0 = hide */
static const int topbar             = 1; /* 1 = top, 0 = bottom    */
static const int resizehints        = 1; /* 1 = respect size hints, 0 = ignore */

resizehints 1 lets terminal windows dictate their own size, which can leave gaps between windows and screen edges in tiling mode. Most users set this to 0 to fill the screen completely.

Tags (Workspaces)

static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" };

Tags can be renamed to any string:

static const char *tags[] = { "web", "term", "edit", "mail", "5", "6", "7", "8", "9" };

Rules (Application Placement)

Rules define where an application opens and whether it floats. Without a rule, a window opens on whatever tag is currently active. With a rule, it always opens on a specific tag regardless of where you are.

A practical example: you want Firefox to always open on tag 1. You are on tag 2. You launch Firefox. It opens on tag 1. You switch to tag 1 to use it. The other tags have no rules — windows there follow normal behaviour.

static const Rule rules[] = {
    /* class     instance  title  tags mask  isfloating  monitor */
    { "Firefox", NULL,     NULL,  1 << 0,    1,          -1 },
    { "feh",     NULL,     NULL,  0,         1,          -1 },
};

tags mask controls which tag the window opens on. 1 << 0 means tag 1, 1 << 1 means tag 2, 1 << 8 means tag 9. 0 means no specific tag — just respect isfloating.

isfloating 1 makes the window always float. monitor -1 means follow the current monitor.

Windows with no matching rule open on the current active tag, tiled.

To find a window’s class name, run:

xprop | grep WM_CLASS

then click the window. Use the second value returned (the class, not the instance).

Layouts

static const float mfact = 0.55; /* master area size: 0.05 to 0.95 */
static const int nmaster  = 1;   /* number of windows in master area */

static const Layout layouts[] = {
    { "[]=", tile    }, /* tiling   — first entry is the default */
    { "><>", NULL    }, /* floating */
    { "[M]", monocle }, /* monocle  */
};

Adjust mfact to change how much screen the master area takes. 0.55 means the master takes 55% of the screen width.

Keybindings

MODKEY is defined near the top:

#define MODKEY Mod1Mask   /* Alt key (default) */
/* #define MODKEY Mod4Mask   Super / Windows key — uncomment to use instead */

Using Two Modifier Keys

Some users prefer to split bindings across two modifiers — one for window management and one for application launchers. This is a personal workflow choice, not a requirement.

#define MODKEY  Mod1Mask   /* Alt   — window management     */
#define MODKEY2 Mod4Mask   /* Super — application launchers */

Then use MODKEY2 selectively inside keys[]:

{ MODKEY,   XK_j, focusstack, {.i = +1 } },         /* Alt+j   focus next window */
{ MODKEY2,  XK_f, spawn,      {.v = browsercmd } },  /* Super+f launch browser    */

Default Bindings

Alt + p                  launch dmenu
Alt + Shift + Return     launch terminal (st)
Alt + b                  toggle bar
Alt + j / k              focus next / previous window
Alt + i / d              increase / decrease windows in master
Alt + h / l              resize master area left / right
Alt + Return             toggle window between master and stack
Alt + Tab                switch to previous tag
Alt + Shift + c          close focused window
Alt + t                  tiling layout
Alt + f                  floating layout
Alt + m                  monocle layout
Alt + Space              toggle between last two layouts
Alt + Shift + Space      toggle floating on focused window
Alt + 0                  show all tags
Alt + 1..9               switch to tag 1..9
Alt + Shift + 1..9       move focused window to tag 1..9
Alt + Comma / Period     focus previous / next monitor
Alt + Shift + q          quit dwm

Adding a Keybinding

Find the keys[] array and add a line following this pattern:

static const Key keys[] = {
    /* modifier          key        function   argument */
    { MODKEY,            XK_p,      spawn,     {.v = dmenucmd } },
    { MODKEY|ShiftMask,  XK_Return, spawn,     {.v = termcmd  } },
};

To launch a custom program, add a command array and a binding:

static const char *browsercmd[] = { "firefox", NULL };

{ MODKEY, XK_w, spawn, {.v = browsercmd } },

Each argument must be a separate string in the array. Do not put the full command inside a single string:

/* wrong — dwm will not parse spaces */
static const char *browsercmd[] = { "firefox --private-window", NULL };

/* correct */
static const char *browsercmd[] = { "firefox", "--private-window", NULL };

Key symbols (XK_p, XK_w, etc.) are defined in the X11 keysym headers (usually /usr/include/X11/keysymdef.h). To find the symbol for any key, use xev:

xev | grep keysym

Press the key in the xev window and read the symbol from the output.

Launching a Program and Keeping the Terminal Open

Some terminals support a --hold flag to keep the window open after the command exits. st does not. Use the shell instead:

static const char *fetchcmd[] = { "st", "-e", "sh", "-c", "fastfetch; read", NULL };

{ MODKEY, XK_F5, spawn, {.v = fetchcmd} },

read pauses until you press Enter. Keep st minimal — let the shell handle it.

Mouse Bindings

/* click            mod     button   function           */
{ ClkClientWin,  MODKEY, Button1, movemouse      }, /* MOD + left drag  = move         */
{ ClkClientWin,  MODKEY, Button2, togglefloating }, /* MOD + middle     = toggle float */
{ ClkClientWin,  MODKEY, Button3, resizemouse    }, /* MOD + right drag = resize       */
{ ClkTagBar,     0,      Button1, view           }, /* click tag        = switch tag   */
{ ClkTagBar,     0,      Button3, toggleview     }, /* right click tag  = toggle tag   */

dmenu Colors

dmenu picks up the color variables directly:

static const char *dmenucmd[] = {
    "dmenu_run",
    "-nb", col_gray1,  /* normal background */
    "-nf", col_gray3,  /* normal foreground */
    "-sb", col_cyan,   /* selected background */
    "-sf", col_gray4,  /* selected foreground */
    NULL
};

To change dmenu colors independently from the rest of dwm, replace the variable references with literal hex strings:

"-sb", "#e0b800",

Common Tasks at a Glance

Want to change

Where to look

Window border color

col_gray2 (unfocused), col_cyan (focused)

Bar background

col_gray1 and col_cyan in colors[]

Font

fonts[] and dmenufont

Correct font name

fc-list | grep -i "name"

Bar position

topbar

Master area size

mfact

Default layout

first entry in layouts[]

App always floating

isfloating 1 in rules[]

App opens on tag N

1 << (N-1) in rules[]

Modifier key

#define MODKEY

Two modifier keys

define MODKEY2 with a second Mod*Mask

Add a launcher

new const char *cmd[] + entry in keys[]

Find a window class

xprop | grep WM_CLASS

Find a key symbol

xev | grep keysym

Remove tiling gaps

resizehints = 0


Project repository: https://git.suckless.org/dwm

Based on the vanilla config.def.h. Keep your config.h in sync with upstream config.def.h after updates.

Slackware

Slackware users may alternatively build dwm using a SlackBuild and include their custom config.h during the build process.

A minimal SlackBuild example (without additional patches) is available at: https://github.com/r1w1s1/slackbuilds/tree/master/OVERLAY/desktop/dwm