Kernel Configuration
Before a single line of kernel code gets compiled, you need a valid .config. Here is how the kernel figures out where to start.
What you will learn in this part
- Why a starting .config is critical before you build the kernel
- How the kernel’s DEFCONFIG_LIST priority system works
- All the configuration front-ends: menuconfig, xconfig, nconfig, oldconfig
- What happens when no .config exists at all
- How to read and understand any .config file
- The difference between a learning config and a production config
1. The Big Picture — What Has to Happen Before make
You have downloaded the Linux kernel source. You want to build it. Your first instinct might be to just run make. But if you do that without a .config file present in the kernel source root, the build will either fail or pull in a giant default configuration you did not plan for.
The configuration step is not optional — it is the foundation. Think of building a kernel like constructing a building. The .config file is your blueprint. Without it, the builders (compiler and Makefiles) do not know what to build, how big to make it, or which features to include.
2. The DEFCONFIG_LIST — How Kbuild Finds a Starting Config
What happens if you type make menuconfig in the kernel source directory but there is no .config file yet? The kernel build system does not crash — it uses a clever fallback priority list to find a starting configuration.
This priority list is defined in init/Kconfig inside a special entry called DEFCONFIG_LIST. Here is what it looks like in a modern 6.x kernel:
# init/Kconfig (Linux 6.x — simplified)
config DEFCONFIG_LIST
string
depends on !UML
option defconfig_list
default "/lib/modules/$(shell,uname -r)/.config"
default "/etc/kernel-config"
default "/boot/config-$(shell,uname -r)"
default ARCH_DEFCONFIG
default "arch/$(ARCH)/defconfig"
The Kbuild system walks through this list from top to bottom and stops at the first match it finds. Let us understand each entry:
/lib/modules/$(uname -r)/.config
The config file from your currently running kernel’s module directory. Most common on desktop/server Linux systems.
/etc/kernel-config
A system-wide kernel config file. Rarely present, but allows administrators to place a standard config in a fixed location.
/boot/config-$(uname -r)
The config your Linux distribution ships with alongside its pre-built kernel. This is very commonly found on Ubuntu, Fedora, Debian systems.
ARCH_DEFCONFIG
An architecture-specific default. Each CPU architecture (x86, ARM, RISC-V, etc.) has a minimal working default defined in its own Kconfig.
arch/$(ARCH)/defconfig
A built-in minimal defconfig file inside the kernel source tree for the current architecture. The last resort — always exists.
.config file already exists in the kernel source root directory, the entire DEFCONFIG_LIST is ignored. The existing .config always takes priority over everything. This means once you have set up your config, re-running make menuconfig will always start from your existing choices.
Check What Config Files Are Available on Your System
Before you start configuring, it is useful to know what is already available on your machine:
# Check your running kernel version
uname -r
# See if /lib/modules config exists (priority 1)
ls /lib/modules/$(uname -r)/.config 2>/dev/null && echo "Found!" || echo "Not present"
# See if /boot config exists (priority 3 — most common on Ubuntu/Debian/Fedora)
ls /boot/config-$(uname -r) 2>/dev/null && echo "Found!" || echo "Not present"
# On Ubuntu/Debian, your running kernel config is often available here too
zcat /proc/config.gz 2>/dev/null | head -5 # Only if CONFIG_IKCONFIG_PROC=y
/boot/config-$(uname -r) already present. This is the configuration that Canonical used to build your current running kernel. It is an excellent starting point when you want to build a custom kernel for your own machine.
3. The Configuration Front-Ends
The kernel provides several ways to interact with the configuration. Under the hood, they all do the same thing — read the Kconfig files and write to your .config file. The difference is the user interface.
Automation-Friendly Config Targets
Beyond the interactive UIs, there are several non-interactive config targets that are extremely useful in scripted or CI/CD environments:
| make target | What it does |
|---|---|
make defconfig |
Creates a minimal default .config for your current architecture. Good starting point on embedded targets. |
make oldconfig |
Takes an existing .config and asks you about only the new options added since that config was created. Very useful when upgrading kernel versions. |
make olddefconfig |
Like oldconfig but automatically sets all new options to their default values — no prompts. Very handy in automated builds. |
make localmodconfig |
Scans currently loaded kernel modules and creates a minimal config containing only those. Produces a lean kernel tailored for your current system. |
make listnewconfig |
Lists all new config options that appear in the new kernel but are missing from your current .config. Useful before running oldconfig. |
4. Anatomy of a .config File
Let us take a detailed look at a real .config snippet and understand every part of it:
#
# Automatically generated file; DO NOT EDIT.
# Linux/x86_64 6.12.0 Kernel Configuration
# ← Header comment — never edit above this
CONFIG_CC_VERSION_TEXT="gcc (Ubuntu 13.2.0)" ← Compiler info (auto-detected)
CONFIG_CLANG_VERSION=0
CONFIG_64BIT=y ← 64-bit kernel (y = built-in)
CONFIG_X86_64=y ← Target is x86_64 architecture
#
# General setup ← Section comment — these are just labels
#
CONFIG_LOCALVERSION="" ← Empty = no suffix on kernel version
CONFIG_LOCALVERSION_AUTO=y ← Auto-append git hash to version
# CONFIG_SWAP is not set ← This feature is DISABLED (n)
CONFIG_SYSVIPC=y ← System V IPC is enabled, built-in
#
# Kernel features
#
CONFIG_HZ_250=y ← Select 250 HZ timer option
CONFIG_HZ=250 ← Numeric config = 250 ticks/sec
CONFIG_PREEMPTION=y ← Preemptible kernel enabled
#
# Loadable module support
#
CONFIG_MODULES=y ← Module support enabled
CONFIG_MODULE_UNLOAD=y ← Allow unloading modules
CONFIG_MODULE_FORCE_UNLOAD=y ← Force unload even if in use
#
# Networking
#
CONFIG_NET=y ← Core networking stack: built-in
CONFIG_PACKET=y ← Raw packet sockets: built-in
CONFIG_BT=m ← Bluetooth: built as a module
# CONFIG_WIRELESS is not set ← WiFi: disabled completely
🔍 Three patterns you will see in every .config
5. Learning Config vs Production Config — An Important Distinction
This is something that many tutorials skip over, but it is really important to understand before you start experimenting.
- Use any starting config you like
- Run on a virtual machine or spare hardware
- Try different options to see what breaks
- Compile the whole thing including debug symbols
- Build failures are learning opportunities
- No real consequence if the kernel does not boot
- Always start from a known working config
- Test on identical hardware before deploying
- Make one change at a time and verify
- Keep your .config in version control
- Keep a fallback/rescue kernel always available
- Breakage can affect real users and real systems
6. How to Find and Identify Config Options
When you are configuring a kernel, you often need to find a specific option. Here are the practical ways to do that:
Using the Search Feature in menuconfig
Inside make menuconfig, press the / key to open a search dialog. Type the feature name or CONFIG symbol you are looking for:
Press / in menuconfig, then type:
BT → Finds CONFIG_BT (Bluetooth)
EXT4 → Finds CONFIG_EXT4_FS
USB_SERIAL → Finds USB serial port driver option
The search results show:
- The full config name (CONFIG_BT)
- Its current value (y/m/n)
- Where it is located in the menu tree
- Which options it depends on
- Which options it selects automatically
Using grep on the .config File
# Check if Bluetooth is enabled and how
grep CONFIG_BT /boot/config-$(uname -r)
# Output: CONFIG_BT=m
# Find all USB-related options
grep CONFIG_USB /boot/config-$(uname -r) | head -20
# Find all options currently set to 'm' (modules)
grep "=m$" /boot/config-$(uname -r) | wc -l
# Typical output on Ubuntu: 4000+ modules!
Using scripts/config — The Scriptable Way
The kernel source includes a helper script at scripts/config that lets you read and set config values from the command line — very useful for automated builds:
# Check the current value of an option
scripts/config --state CONFIG_BT
# Output: m
# Enable an option as built-in
scripts/config --enable CONFIG_BT
# Set an option as a module
scripts/config --module CONFIG_BT
# Disable an option completely
scripts/config --disable CONFIG_WIRELESS
# Set a string value
scripts/config --set-str CONFIG_LOCALVERSION "-mykernel"
# After using scripts/config, run this to clean up any dependency issues:
make olddefconfig
Part 2 — Quick Recap
- A
.configfile must exist before the build can start - Kbuild uses DEFCONFIG_LIST to find a starting config when no .config is present — it walks through five fallback locations in order
- If a
.configalready exists in the kernel source root, it overrides everything in DEFCONFIG_LIST - Multiple front-ends exist:
menuconfig(most popular),nconfig,xconfig,gconfig - Non-interactive targets like
olddefconfigandlocalmodconfigare great for automation - For production, always start from a known-good, tested config and keep it in version control

2 Comments