If your Debian box “randomly” freezes under load, or your build server starts timing out the moment RAM hits 95%, swap is often involved—either missing, misconfigured, or quietly slow. Swapfile setup looks like a five-minute chore until you discover that a single wrong assumption (permissions, filesystem quirks, priority, or a bad fstab line) can turn memory pressure into a production incident.
This is a field guide for Debian 13: how to create a swapfile correctly, how to prove it’s actually used, and how to diagnose the failures that show up at 02:00 when you’d rather be asleep.
Facts & context (why swapfiles still bite)
Swapfiles are not new. What’s new is how many layers can interfere: copy-on-write filesystems, encryption, cgroups memory limits, zram, and systemd unit ordering. A swapfile can exist, be “enabled,” and still be useless (or harmful) if it’s slow, fragmented, on the wrong filesystem, or competing with another swap device at a higher priority.
8 short facts and bits of history
- Swap predates Linux: UNIX-like systems have used paging since the 1970s; Linux inherited the concept early and has iterated heavily on VM behavior since.
- Swap partitions used to be the default answer because they were predictable: contiguous blocks, no filesystem metadata surprises.
- Swapfiles were historically “second-class” on some filesystems because block mapping was harder, fragmentation mattered more, and hibernation requirements were strict.
- Modern kernels can use swapfiles efficiently on traditional filesystems (ext4/XFS) if the file is properly allocated and not sparse—yet people still create sparse swapfiles by accident.
- Btrfs made swapfiles complicated: copy-on-write and compression clash with swap’s expectations. Modern kernels support it with constraints (nocow, no compression, correct allocation), but it’s still easy to do wrong.
- Priority has existed for a long time: Linux can stripe swap I/O across areas of equal priority; it’s not just “pick one.” Mis-set priorities create surprising behavior.
- Swappiness is not a “speed knob”; it’s a policy knob. Many teams misuse it as a performance fix, then wonder why latency worsened under pressure.
- Hibernation is a different beast: it requires the resume path to find the exact swap area where the image lives; swapfiles can work, but only if the resume configuration matches reality.
One quote worth keeping above your terminal:
“Hope is not a strategy.” — Gen. Gordon R. Sullivan
Swap configuration is the perfect place to stop hoping.
What “good” looks like on Debian 13
A correct Debian 13 swapfile setup has these properties:
- The swapfile is non-sparse (real blocks allocated).
- Permissions are 0600, owned by root.
- It lives on a filesystem that supports swapfiles safely for your use case (ext4 and XFS are boring-good; Btrfs requires extra care; ZFS is a special conversation).
- It’s enabled at boot via
/etc/fstab(or a systemd unit), and you can prove it withswapon --show. - Priority is deliberate: you know which swap area should be used first, and why.
- Monitoring is in place: you can see memory pressure, swap usage, and major page faults before users report timeouts.
Two swap truths you can pin on the wall:
- Swap is not a substitute for capacity planning. It’s a safety net, not a mattress.
- If you rely on swap for steady-state performance, you’re building a latency generator.
Joke #1: Swap is like caffeine: helpful in emergencies, but if it’s part of your daily diet, something upstream is broken.
Fast diagnosis playbook
When a Debian system feels slow and you suspect swap, you want to identify the bottleneck in minutes, not hours. Here’s the order that consistently gets to root cause.
First: confirm swap exists and is active
- Check enabled swap areas and their priorities.
- Confirm the swapfile isn’t silently ignored due to permissions or filesystem constraints.
Second: confirm you have memory pressure (not just CPU or I/O)
- Check MemAvailable, swap in/out rate, and major faults.
- Look for OOM kills: they’re the loudest symptom of “swap absent or ineffective.”
Third: determine whether swap is helping or hurting
- If swap I/O is high and disk latency spikes, you’re in thrash territory.
- If swap usage is modest but stable and your box stays responsive, swap is doing its job.
Fourth: isolate the culprit workload
- Identify which processes are growing RSS or causing page faults.
- Check cgroup limits and container memory settings if applicable.
Fifth: decide the move
- Short-term: add RAM, add swap, reduce concurrency, or kill runaway processes.
- Medium-term: fix memory leaks, right-size, and ensure swap configuration is sane.
Practical tasks: commands, outputs, decisions
Below are hands-on tasks you can run on Debian 13. Each includes: the command, what typical output means, and what decision you make from it. This is the “stop guessing” kit.
Task 1 — See if swap is enabled (and priority)
cr0x@server:~$ swapon --show --output=NAME,TYPE,SIZE,USED,PRIO
NAME TYPE SIZE USED PRIO
/swapfile file 8G 256M -2
Meaning: Swap is enabled and in use (256M). Priority is -2; negative priorities are normal for swapfiles unless you set it.
Decision: If nothing shows up, you don’t have active swap. Fix before tuning anything else.
Task 2 — Verify swap is recognized in the kernel
cr0x@server:~$ cat /proc/swaps
Filename Type Size Used Priority
/swapfile file 8388604 262144 -2
Meaning: Kernel sees the swapfile; size and used are in KiB.
Decision: If the swapfile is missing here but present on disk, activation failed—check permissions, fstab, and filesystem constraints.
Task 3 — Check memory pressure at a glance
cr0x@server:~$ free -h
total used free shared buff/cache available
Mem: 31Gi 27Gi 1.2Gi 412Mi 3.0Gi 2.8Gi
Swap: 8.0Gi 256Mi 7.8Gi
Meaning: “available” is the best quick indicator; 2.8Gi available suggests pressure is present but not catastrophic. Swap is lightly used.
Decision: If “available” is tiny and swap used is climbing fast, you’re heading into thrash or OOM.
Task 4 — Determine whether swapping is active right now
cr0x@server:~$ vmstat 1 5
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
2 0 262144 1248932 212344 2912456 0 0 12 45 241 512 9 3 87 1 0
1 0 262144 1251120 212352 2911988 0 0 0 16 198 430 7 2 90 1 0
3 1 270336 312144 212360 3014332 512 1024 800 1200 412 980 18 7 52 23 0
2 1 285696 140512 212368 3040012 768 2048 900 1500 430 1100 20 8 41 31 0
1 0 285696 210224 212376 3038008 0 0 110 220 260 600 11 4 83 2 0
Meaning: Columns si/so show swap-in/out per second. Spikes (512/1024 etc.) indicate active swapping.
Decision: If sustained si/so is non-zero and wa rises, you likely have memory pressure plus I/O contention. Identify the workload and consider adding RAM or reducing memory footprint.
Task 5 — Check for OOM kills (the “you had no plan” receipt)
cr0x@server:~$ journalctl -k -g "Out of memory" -n 10 --no-pager
Dec 30 10:12:44 server kernel: Out of memory: Killed process 24891 (java) total-vm:14688208kB, anon-rss:12710492kB, file-rss:1420kB, shmem-rss:0kB, UID:1000 pgtables:27820kB oom_score_adj:0
Meaning: The kernel killed a process because it couldn’t reclaim memory fast enough.
Decision: If OOM happens and swap is absent or tiny, add swap as a safety net—but also fix the memory demand. If swap exists and OOM still occurs, you may have swap unusable (filesystem issue) or memcg limits.
Task 6 — Confirm swapfile permissions (security and correctness)
cr0x@server:~$ ls -lh /swapfile
-rw------- 1 root root 8.0G Dec 30 09:58 /swapfile
Meaning: -rw------- is 0600. That’s what you want. Swap contains potentially sensitive data.
Decision: If you see 0644 or anything not 0600, fix immediately and re-enable swap if needed.
Task 7 — Detect a sparse swapfile (silent performance and activation problems)
cr0x@server:~$ filefrag -v /swapfile | head
Filesystem type is: ef53
File size of /swapfile is 8589934592 (2097152 blocks of 4096 bytes)
ext: logical_offset: physical_offset: length: expected: flags:
0: 0.. 65535: 532480.. 598015: 65536:
1: 65536.. 131071: 598016.. 663551: 65536:
2: 131072.. 196607: 663552.. 729087: 65536:
/swapfile: 3 extents found
Meaning: Few extents is good: likely contiguous enough. A sparse file would show holes, and some tools will warn on activation.
Decision: If you see many extents (hundreds/thousands) on spinning disks, expect swap I/O to be painful. Recreate the swapfile with a method that allocates contiguously, and keep it on fast storage.
Task 8 — Confirm filesystem type under the swapfile
cr0x@server:~$ findmnt -no FSTYPE,TARGET /swapfile
ext4 /
Meaning: Swapfile is on ext4: generally safe and straightforward.
Decision: If it’s on btrfs or zfs, read the filesystem pitfall section before declaring victory.
Task 9 — Check your fstab entry is being used (and not ignored)
cr0x@server:~$ grep -nE 'swap|swapfile' /etc/fstab
12:/swapfile none swap sw,pri=10 0 0
Meaning: You have an explicit swapfile entry with priority 10.
Decision: If there’s no swap line, you’re relying on manual swapon or a distro helper. For servers, make boot behavior deterministic via fstab or systemd.
Task 10 — Test activation now (catch errors immediately)
cr0x@server:~$ sudo swapoff /swapfile
cr0x@server:~$ sudo swapon /swapfile
cr0x@server:~$ swapon --show
NAME TYPE SIZE USED PRIO
/swapfile file 8G 0B 10
Meaning: Re-activation succeeded and priority applied.
Decision: If swapon errors (permissions, holes, unsupported), fix the underlying issue rather than forcing it.
Task 11 — Measure swap device I/O latency symptoms
cr0x@server:~$ iostat -xz 1 3
Linux 6.12.0-amd64 (server) 12/30/25 _x86_64_ (16 CPU)
avg-cpu: %user %nice %system %iowait %steal %idle
14.21 0.00 5.10 18.33 0.00 62.36
Device r/s rkB/s rrqm/s %rrqm r_await rareq-sz w/s wkB/s wrqm/s %wrqm w_await wareq-sz aqu-sz %util
nvme0n1 8.00 512.0 0.00 0.00 0.45 64.0 65.00 8192.0 0.00 0.00 4.80 126.0 0.32 12.00
Meaning: Elevated iowait plus high write rates could be swap-out. On NVMe, a few ms might be fine; on HDD, this is where systems go to die slowly.
Decision: If %iowait and await climb during memory pressure, swap is a contributing factor; move swap to faster storage or reduce swapping.
Task 12 — Inspect swappiness and decide if you should touch it
cr0x@server:~$ sysctl vm.swappiness
vm.swappiness = 60
Meaning: Default-ish behavior: the kernel will swap out under memory pressure with a balanced policy.
Decision: Don’t cargo-cult vm.swappiness=1. Adjust only with a clear objective: e.g., latency-sensitive workloads that should avoid swap, or memory-constrained systems where you’d rather reclaim cache earlier.
Task 13 — Confirm whether zram is present (and competing)
cr0x@server:~$ swapon --show --output=NAME,TYPE,SIZE,USED,PRIO
/dev/zram0 partition 2G 0B 100
/swapfile file 8G 0B 10
Meaning: zram has much higher priority, so it will be used first.
Decision: This is usually fine (compressed RAM swap is fast), but you must know it exists or you’ll misread performance results. If zram is too small, you may still hit disk swap under heavy pressure.
Task 14 — If you care about hibernation: locate swap offset (swapfile only)
cr0x@server:~$ sudo filefrag -v /swapfile | awk '/^ *0:/{print $4}' | tr -d '.'
532480
Meaning: This is the physical offset of the first extent (filesystem-block units), used by some hibernation setups to compute resume_offset.
Decision: If you hibernate, you need a stable swapfile mapping and correct resume configuration. If you don’t hibernate, don’t overfit your system to a use case you don’t have.
Create a swapfile the boring correct way
There are two broad approaches: allocate blocks with fallocate, or write zeroes with dd. On modern ext4/XFS, fallocate is usually fast and correct. On some filesystems or configurations, fallocate can create extents in ways you don’t want, or it may fail outright. The point isn’t ideology; it’s predictable behavior.
Recommended: ext4/XFS swapfile using fallocate
This is the clean path for most Debian 13 servers on ext4/XFS.
cr0x@server:~$ sudo swapoff -a
cr0x@server:~$ sudo rm -f /swapfile
cr0x@server:~$ sudo fallocate -l 8G /swapfile
cr0x@server:~$ sudo chmod 600 /swapfile
cr0x@server:~$ sudo mkswap /swapfile
Setting up swapspace version 1, size = 8 GiB (8589930496 bytes)
no label, UUID=8b0a9a2e-35e6-4f1a-bf94-7a843e62c2e6
cr0x@server:~$ sudo swapon /swapfile
cr0x@server:~$ swapon --show
NAME TYPE SIZE USED PRIO
/swapfile file 8G 0B -2
Why these steps, in this order:
swapoff -aensures you’re not modifying an active swap area (yes, people do).- Recreating avoids inherited weirdness (holes, compression flags, CoW). Swap is not a snowflake; treat it as replaceable.
chmod 600prevents leakage and stopsswaponfrom complaining or refusing in stricter environments.mkswapwrites the swap header. Without it, the kernel doesn’t know what the file is supposed to be.
When to use dd instead
If you’re on a filesystem where fallocate yields a sparse-ish file, fails, or produces odd extents, use dd to force allocation. It’s slower, but it tends to be honest.
cr0x@server:~$ sudo rm -f /swapfile
cr0x@server:~$ sudo dd if=/dev/zero of=/swapfile bs=1M count=8192 status=progress
8589934592 bytes (8.6 GB, 8.0 GiB) copied, 9 s, 954 MB/s
8192+0 records in
8192+0 records out
8589934592 bytes (8.6 GB, 8.0 GiB) copied, 9.00726 s, 953 MB/s
cr0x@server:~$ sudo chmod 600 /swapfile
cr0x@server:~$ sudo mkswap /swapfile
Setting up swapspace version 1, size = 8 GiB (8589930496 bytes)
no label, UUID=52b75f13-10bd-4b0a-89c7-92b9c2aa9916
cr0x@server:~$ sudo swapon /swapfile
Decision rule: If filefrag shows a ridiculous number of extents, or activation complains about holes, recreate with dd or move the swapfile to a better-suited filesystem.
Joke #2: A sparse swapfile is like a “wireless” power cable—technically a thing, but not the thing you meant.
Security: permissions and where swap data goes
Swap can contain snippets of anything: TLS private key material in memory, session tokens, plaintext credentials that lived in a buffer for a millisecond too long. Your swapfile should be root-owned and mode 0600. That’s not paranoia. That’s Monday.
If your disk is encrypted (LUKS), swap inherits that protection when it lives inside the encrypted volume. If it’s not encrypted and you handle sensitive data, rethink the threat model. “It’s only swap” is how you end up explaining to compliance why memory content was recoverable from a decommissioned drive.
fstab: entries, ordering, and the traps
Swap that doesn’t come up on boot is swap you don’t have. For servers, I like /etc/fstab because it’s explicit and reviewable. You can also use systemd swap units, but you’ll still end up debugging it with the same primitives.
A good swapfile fstab entry
cr0x@server:~$ sudo sh -c 'printf "%s\n" "/swapfile none swap sw,pri=10 0 0" >> /etc/fstab'
cr0x@server:~$ tail -n 3 /etc/fstab
# swap was on /dev/sda3 during installation
/swapfile none swap sw,pri=10 0 0
Meaning: The system will activate /swapfile at boot with priority 10.
Decision: Pick a priority intentionally. If you have multiple swap areas, priority decides who gets used first (and whether the kernel stripes).
Common fstab traps that waste hours
- Wrong path: you created
/swapfilebut wrote/swap.img. - Whitespace or hidden characters: copy/paste from chat can add non-breaking spaces. Yes, I’ve seen it.
- Swapfile on a mount that appears late: if
/swapfilelives on a separate filesystem that fails to mount, swap won’t activate. That failure might be silent unless you read boot logs. - Assuming fstab implies success: it implies an attempt. Verify with
swapon --showafter boot.
Check whether systemd actually activated it
cr0x@server:~$ systemctl status swapfile.swap --no-pager
Unit swapfile.swap could not be found.
Meaning: You don’t have an explicit unit named swapfile.swap. With fstab, systemd generates units dynamically; naming differs based on path encoding.
Decision: Don’t chase unit names first. Confirm activation via swapon, then inspect generated units if needed:
cr0x@server:~$ systemctl list-units --type=swap --all --no-pager
UNIT LOAD ACTIVE SUB DESCRIPTION
dev-zram0.swap loaded active active /dev/zram0
swapfile.swap loaded active active /swapfile
LOAD = Reflects whether the unit definition was loaded.
ACTIVE = The high-level unit activation state.
SUB = The low-level unit activation state.
Decision: If the swap unit is missing or failed, inspect boot logs and the swapfile properties rather than tweaking swappiness as a coping mechanism.
Swap priority: what it does and how to use it
Priority is where “it works on my laptop” goes to become a confusing server behavior. Linux uses swap priority to decide which swap areas to allocate from. Higher priority gets used first. Areas with the same priority may be used in a balanced way (think: spreading I/O), which can be good if you have multiple equally fast devices, and very bad if you accidentally stripe across a fast NVMe and a sad old HDD.
Practical priority patterns
- zram first (high priority): use compressed RAM swap to handle brief pressure without touching disk.
- fast disk swap second: NVMe swapfile/partition as the next tier.
- slow disk swap last (or never): HDD swap can keep the kernel alive, but it will punish latency.
Set priority in fstab
Example: prefer zram, then swapfile.
cr0x@server:~$ sudo sed -i 's#^/swapfile .*#\/swapfile none swap sw,pri=10 0 0#' /etc/fstab
cr0x@server:~$ sudo swapoff /swapfile
cr0x@server:~$ sudo swapon /swapfile
cr0x@server:~$ swapon --show --output=NAME,SIZE,PRIO
NAME SIZE PRIO
/dev/zram0 2G 100
/swapfile 8G 10
Decision: If you see equal priority across mismatched devices, fix it. Predictability beats accidental striping.
Know what “priority -2” means
When you run swapon without specifying priority, the kernel assigns a default. Swap partitions often land with higher default priority than swapfiles depending on how they’re activated. This matters when you have both and assume the “new swapfile” is taking effect—while the system keeps hammering the old swap partition.
cr0x@server:~$ swapon --show --output=NAME,TYPE,SIZE,USED,PRIO
/dev/sda2 partition 4G 1.2G -1
/swapfile file 8G 128M -2
Decision: If you want the swapfile to be preferred, set pri higher than the partition (or disable the partition). Don’t assume.
Filesystem-specific pitfalls (ext4, XFS, Btrfs, ZFS)
This is where most swapfile “gotchas” live. The swap subsystem needs stable block mapping. Some filesystems love moving blocks around for good reasons (copy-on-write, defrag, reflinks). Swap doesn’t share that enthusiasm.
ext4: the default for a reason
ext4 swapfiles are usually safe. Your main risks:
- Creating a sparse file (common when using
truncateor certainfallocatebehaviors on odd setups). - Putting swap on a heavily fragmented filesystem (more painful on HDD than SSD).
- Wrong permissions or forgetting
mkswap.
XFS: also boring-good
XFS swapfiles are generally fine. Like ext4, ensure the file is properly allocated and permissions are correct. XFS is widely used in production, and swapfiles are not exotic there.
Btrfs: possible, but stop improvising
Btrfs has features that conflict with swap: copy-on-write, compression, and potentially dynamic extent mapping. Modern kernels can support swapfiles on Btrfs, but only if the swapfile meets constraints (no CoW, not compressed, and properly allocated). If you don’t understand those constraints, you’ll create a swapfile that activates today and fails after a defrag or a balance.
Sanity checks you should run if the swapfile is on Btrfs:
cr0x@server:~$ findmnt -no FSTYPE,TARGET /swapfile
btrfs /
cr0x@server:~$ lsattr /swapfile
---------------------- /swapfile
Meaning: The file attributes here don’t show NOCOW (C). That’s suspicious on Btrfs.
Decision: For Btrfs swapfile, you generally want NOCOW. One common method is to set it on the file and then allocate it. If you already wrote data, you may need to recreate. Example flow:
cr0x@server:~$ sudo swapoff /swapfile
cr0x@server:~$ sudo rm -f /swapfile
cr0x@server:~$ sudo truncate -s 0 /swapfile
cr0x@server:~$ sudo chattr +C /swapfile
cr0x@server:~$ sudo fallocate -l 8G /swapfile
cr0x@server:~$ sudo chmod 600 /swapfile
cr0x@server:~$ sudo mkswap /swapfile
Setting up swapspace version 1, size = 8 GiB (8589930496 bytes)
no label, UUID=0e1c4a2d-5d8d-4c08-a5c8-40db51b4dfc3
cr0x@server:~$ sudo swapon /swapfile
What to watch for: If swapon errors with “Invalid argument” or complains about holes, the file’s extents aren’t acceptable. Don’t force it; move swap to a swap partition or a non-CoW filesystem.
ZFS: swapfile is usually the wrong tool
On ZFS, swapfiles are notoriously tricky because ZFS is copy-on-write and does not provide the same guarantees swap expects. Many operators use a swap partition or a zvol for swap. If you’re running Debian on ZFS root, your “swapfile on ZFS dataset” plan can become a performance and reliability trap.
Pragmatic guidance:
- If you’re on ZFS and you want swap, prefer a dedicated swap partition or a zvol configured appropriately.
- If you must use a swapfile, test thoroughly under memory pressure, confirm no snapshots/recordsize/compression behaviors are hurting you, and expect unpleasant surprises.
Performance and reliability tuning (what matters, what doesn’t)
Swap performance is mostly about storage latency and avoiding pathological swapping. A perfectly-tuned swapfile on slow storage is still slow storage. Your goal is not “never swap.” Your goal is “stay alive and responsive under expected pressure.”
Swappiness: policy, not magic
Default swappiness (often 60) is fine for general-purpose systems. Lowering it can reduce swapping but may increase pressure on page cache and cause different failure modes (like earlier OOM in certain patterns). Increasing it can keep more cache off RAM, but it may push anonymous pages out earlier, which can hurt interactive latency.
cr0x@server:~$ sudo sysctl -w vm.swappiness=20
vm.swappiness = 20
cr0x@server:~$ sudo sh -c 'printf "%s\n" "vm.swappiness=20" > /etc/sysctl.d/99-swappiness.conf'
cr0x@server:~$ sysctl vm.swappiness
vm.swappiness = 20
Decision: Change swappiness only after you’ve verified swap is correctly configured and you can reproduce the workload pattern. Otherwise you’re just changing how the system fails.
What “swap thrash” looks like
Thrash is when the system spends more time moving pages in and out than doing useful work. Symptoms:
- Load average climbs while CPU idle remains non-zero but iowait spikes.
- Interactive response becomes seconds-to-minutes.
vmstatshows sustained swap-in/out.- Disk latency climbs; queue depth rises.
cr0x@server:~$ cat /proc/pressure/memory
some avg10=0.25 avg60=0.18 avg300=0.10 total=48239210
full avg10=0.07 avg60=0.05 avg300=0.02 total=10293829
Meaning: PSI (Pressure Stall Information) shows time tasks are stalled waiting on memory. “full” indicates stalls severe enough that no progress can be made.
Decision: If “full” is non-trivial during normal operation, you’re underprovisioned or misconfigured. Treat it as a capacity or workload problem, not a swapfile formatting problem.
Priorities and mixed media: don’t stripe NVMe with HDD
If you set equal priority across a fast swap and a slow swap, the kernel may spread swap I/O across both. That drags fast storage down to the pace of the slow one and introduces jitter. Set priorities so the slow device is last resort, or disable it entirely unless you need it purely as an OOM buffer.
Size: “how much swap do I need?”
Rules of thumb are dangerous because workloads vary. Still, in production I use practical sizing:
- General servers: 2–8 GiB swap is often enough as a safety net if you have adequate RAM.
- Build/test runners and JVM-heavy hosts: larger swap can buy time during spikes, but you must monitor latency.
- Hibernation: swap needs to accommodate the hibernation image (often near RAM size, sometimes less with compression, but don’t gamble).
When in doubt: size swap to handle a short spike and keep the kernel from panic/OOM, not to make an under-RAMed system “fine.”
Three corporate mini-stories from the swapfile trenches
Mini-story 1: The incident caused by a wrong assumption
A mid-sized company ran Debian on a fleet of CI workers. They standardized an “8G swapfile everywhere” hardening step. Someone wrote an automation snippet that did: create file, run mkswap, add to fstab, done. It worked in staging. It mostly worked in production. “Mostly” is where incidents come from.
The workers had a mix of filesystems because procurement had a personality: older nodes were ext4; newer nodes were Btrfs because someone wanted snapshots. The automation didn’t detect filesystem type. On Btrfs nodes, the swapfile existed but activation would fail on some boots and succeed on others after maintenance operations. The symptoms were inconsistent: some nodes were fine, others would suddenly OOM-kill builds during peak hours.
The wrong assumption was simple: “a swapfile is a swapfile.” It isn’t. Filesystem behavior matters, especially copy-on-write and defrag semantics. The team lost a day chasing “random kernel behavior” and “JDK memory leaks” before someone compared swapon --show across nodes and noticed half the fleet had no active swap.
The fix was boring and decisive: detect Btrfs, create swap on a dedicated swap partition for those hosts (or configure Btrfs swap correctly with NOCOW and recreate), and add a boot-time check that alerts if swap isn’t active. The incident wasn’t about swap size; it was about a missing safety net.
Mini-story 2: The optimization that backfired
A fintech team had a latency-sensitive API. Someone read that swap causes latency, which is true in the same way that fire causes heat. They set vm.swappiness=1 fleet-wide and reduced swap size to near-zero. Metrics looked great—until a deployment introduced a modest memory increase.
Under normal load, the services ran fine. Under peak load, memory pressure rose, file cache couldn’t be reclaimed enough, and the kernel started OOM-killing processes instead of swapping out cold pages. The “optimization” turned a gradual degradation into a cliff: requests stopped, pods restarted, and the team experienced a classic cascading failure as retries amplified the problem.
They had optimized for the happy path and removed the buffer for the unhappy path. The most frustrating part: the incident wasn’t even a giant memory leak. It was a new feature plus a traffic spike plus the absence of a safety net.
They rolled back swappiness to a sane value, restored swap capacity, and introduced a policy: reduce swapping by fixing memory usage, not by disabling swap. Swap became what it should be: the thing that buys you time to intervene instead of the thing that hides chronic underprovisioning.
Mini-story 3: The boring correct practice that saved the day
An enterprise internal platform team ran Debian 13 on a set of stateful workers. They did a dull thing that few teams prioritize: a boot-time verification script that checked swap activation and logged a clear error if it wasn’t present. It was part of their “node readiness” check, right next to disk space and NTP sanity.
During a routine kernel upgrade cycle, one subset of nodes stopped enabling swap after reboot. The reason wasn’t glamorous: a storage change altered mount ordering, and the swapfile path became temporarily unavailable at the moment systemd tried to activate it. No one noticed immediately—except the readiness check, which flagged nodes as unhealthy and prevented workloads from scheduling there.
That prevented a messy incident. The team had time to inspect journalctl, adjust ordering (and in a couple cases relocate swap), and reintroduce nodes gradually. Users never knew. Leadership never asked why latency charts looked like a seismograph. It was the kind of quiet success you only get with boring controls.
The lesson: swap isn’t only about performance; it’s about operability. A predictable system beats a clever one.
Common mistakes: symptom → root cause → fix
This section is the “I just want it fixed” map. Each mistake is specific, reproducible, and common enough to deserve a scar.
1) Swapfile exists but not listed in swapon
Symptom: ls /swapfile shows the file, but swapon --show is empty or missing it.
Root cause: Swap not activated (fstab missing/wrong) or activation failed at boot.
Fix: Run sudo mkswap /swapfile (if needed) then sudo swapon /swapfile. Add correct fstab entry and confirm after reboot.
2) swapon fails with “Operation not permitted” or “permission denied”
Symptom: sudo swapon /swapfile errors.
Root cause: Permissions not 0600, wrong owner, or security policy enforcement.
Fix: sudo chown root:root /swapfile && sudo chmod 600 /swapfile, then retry.
3) swapon fails with “Invalid argument” on Btrfs
Symptom: Activation fails despite correct permissions.
Root cause: Swapfile on Btrfs with CoW/compression or unsupported extents/holes.
Fix: Recreate swapfile with NOCOW (chattr +C before allocation), ensure it’s not compressed, or use a swap partition/zvol.
4) System boots, but swap sometimes missing after reboot
Symptom: Swap present on some boots, missing on others.
Root cause: Race/ordering: swapfile on a filesystem not mounted when swap activation runs; or filesystem maintenance changed extent mapping in a way swap doesn’t like.
Fix: Put swap on root filesystem or ensure the underlying mount is stable early; verify systemd swap unit dependencies; consider a swap partition for reliability.
5) Heavy swapping causes 10x latency and timeouts
Symptom: Response time explodes; vmstat shows sustained si/so; iowait spikes.
Root cause: Working set doesn’t fit RAM; swap on slow storage; or too much memory overcommit from concurrency.
Fix: Reduce memory footprint or concurrency, add RAM, move swap to faster media, and treat swap as emergency buffer rather than steady-state RAM substitute.
6) Swap is used, but the wrong swap area is used first
Symptom: You added a fast NVMe swapfile but system keeps swapping to HDD partition.
Root cause: Priorities favor the partition, or equal priorities cause striping across both.
Fix: Set explicit pri= in fstab or via swapon -p to prefer the faster swap, and demote/disable slow swap.
7) Hibernation fails after switching to a swapfile
Symptom: Resume fails; system cold boots instead.
Root cause: Resume configuration not updated for swapfile offset; swapfile moved/changed extents.
Fix: Compute the correct resume offset and update initramfs configuration appropriately, or use a dedicated swap partition for hibernation stability.
8) “No swap” was intentional, and now you get OOM kills
Symptom: Processes get killed under spikes; system unstable.
Root cause: Removing swap removed your buffer; memory spikes are now fatal.
Fix: Reintroduce modest swap (and monitor), then fix memory usage and right-size hosts.
Checklists / step-by-step plan
Plan A: Standard Debian 13 server on ext4/XFS (swapfile)
- Confirm filesystem:
findmnt -no FSTYPE,TARGET /swapfile. If ext4/XFS, proceed. - Pick size: start with 4–8 GiB unless you have a known need (hibernation or huge spikes).
- Create swapfile:
fallocate -l 8G /swapfile. - Set permissions:
chmod 600 /swapfile; verify withls -l. - Initialize:
mkswap /swapfile. - Enable now:
swapon /swapfile; verify withswapon --show. - Make persistent: add
/swapfile none swap sw,pri=10 0 0to/etc/fstab. - Reboot test: reboot during a maintenance window; verify swap active post-boot.
- Monitor: track swap usage, PSI memory, and OOM events; alert when swap use spikes or “full” pressure is non-zero for extended periods.
Plan B: Btrfs root (swapfile only if you know the constraints)
- Decide if a swap partition is easier: for many production systems, it is.
- If using swapfile: create the file with NOCOW before allocating blocks.
- Ensure no compression: don’t store swapfile on a compressed subvolume/dataset configuration.
- Recreate rather than modify: treat swapfile as immutable. If you change attributes after writing, you’re asking for trouble.
- Verify activation now and after reboot: if it’s flaky, stop and switch approaches.
Plan C: Multiple swap areas (zram + disk swap)
- Decide priority order: zram highest; NVMe swap next; HDD swap last.
- Explicitly set priorities: don’t rely on defaults.
- Verify effective order:
swapon --show --output=NAME,PRIO. - Load test memory pressure: prove the system degrades gracefully and doesn’t thrash.
FAQ
1) Should I use a swap partition or a swapfile on Debian 13?
On ext4/XFS: swapfile is fine and easier to resize. If you need hibernation reliability or you’re on tricky filesystems (notably Btrfs/ZFS), a partition (or zvol on ZFS) is often the safer choice.
2) What permissions should a swapfile have?
0600, owned by root. Anything else is a data exposure risk and can also cause activation failures depending on policy.
3) Why does my swapfile show priority -2?
That’s a default-assigned priority when you don’t specify one. It’s not automatically wrong. It becomes wrong when you have multiple swap areas and you care which one is used first.
4) Is fallocate always safe for swapfiles?
Usually safe on ext4/XFS. Not universally safe on every filesystem and configuration. If activation complains about holes or the file is weirdly fragmented, recreate using dd or move swap to a simpler filesystem.
5) How do I know if swap is hurting performance?
Look for sustained swap-in/out (vmstat), rising iowait (iostat), and increased “full” memory pressure (PSI). If response latency spikes alongside those, you’re thrashing.
6) Can I put a swapfile on Btrfs?
Yes, but only if you follow constraints (no CoW, no compression, stable allocation). If you can’t guarantee that, use a swap partition. Reliability beats novelty.
7) How big should my swapfile be for servers?
Commonly 4–8 GiB as a safety net, then adjust based on observed spikes and incident history. If you need hibernation, size it for that use case explicitly.
8) Should I set vm.swappiness to 1 for performance?
Not by default. It can reduce swapping, but it can also increase the chance of OOM kills under spikes. Tune with workload evidence, not internet folklore.
9) Why does swap not enable at boot even though fstab is correct?
Often mount ordering: the swapfile sits on a filesystem that isn’t available when swap activation runs. Check boot logs and systemd-generated swap units, and consider relocating swap.
10) Is zram a replacement for disk swap?
It’s a complement. zram is great for absorbing short spikes quickly. Under sustained pressure, you may still need disk swap—or more RAM—depending on workload.
Conclusion: next steps that actually reduce risk
If you run Debian 13 in production, treat swap as part of system design, not a checkbox. Your next steps are simple and practical:
- Audit swap state fleet-wide: confirm swap is enabled, priorities are intentional, and activation is consistent across reboots.
- Fix correctness first: permissions 0600, non-sparse allocation, and filesystem suitability.
- Make boot behavior deterministic: fstab (or explicit systemd swap units), plus a health check that alerts when swap is missing.
- Measure memory pressure: use
vmstat, PSI, and logs for OOM events; don’t rely on user complaints as monitoring. - Use priority to avoid surprises: keep fast swap fast, and keep slow swap as a last resort if you keep it at all.
Swap won’t fix a memory leak. It will, however, keep your systems standing long enough for you to fix the real problem. That’s a trade I’ll take.