A solution for Electron apps that freeze Linux due to excessive resource usage.
Resource limits for Electron apps — a lightweight systemd user service that auto-detects Electron processes and cgroups them with CPU, memory, and PID limits. No root required.
Electron apps (VS Code, Slack, Discord, Spotify, etc.) are notorious resource hogs. A single app can eat 2+ GB of RAM and spike CPU indefinitely. This tool caps each Electron instance at sane defaults so one misbehaving app can't starve the rest of your system.
- Zero config — works out of the box with sensible defaults
- Auto-detection — catches all running Electron processes (main + renderer threads) across 12 categories (~160 apps)
- Cgroup v2 — kernel-native resource enforcement, no per-app daemon overhead
- User-level — runs as a
systemd --userservice, no sudo needed - Configurable — tweak CPU %, memory cap, PID limit via env file or
systemctl set-environment - Persistent — enabled by default; survives reboots
One-liner (curl pipe to bash):
curl -fsSL https://raw.githubusercontent.com/lleqsnoom/electron-shield/main/install.sh | bashOr clone and run locally:
git clone https://github.com/lleqsnoom/electron-shield.git
cd electron-shield
bash install.shThe installer:
- Drops
electron-shield.serviceinto your systemd user dir - Installs the daemon script to
~/.local/bin/ - Creates a config file at
~/.config/electron-shield.conf - Enables and starts the service
Edit ~/.config/electron-shield.conf:
# CPU limit per cgroup (supports percentage or ms/period ratio)
ELECTRON_CPU_MAX=50%
# Memory limit per cgroup
ELECTRON_MEM_MAX=1G
# Maximum PIDs in the electron-shield cgroup
ELECTRON_PIDS_MAX=64
# Detection loop interval (seconds)
ELECTRON_INTERVAL=5
# Custom cgroup name (internal — default: electron-shield)
# ELECTRON_CGROUP_NAME=electron-shieldOr set live via systemd:
systemctl --user set-environment ELECTRON_CPU_MAX=30%
systemctl --user set-environment ELECTRON_MEM_MAX=512M
systemctl --user daemon-reload
systemctl --user restart electron-shieldElectron Shield auto-detects Electron apps via two methods:
- Binary name —
/proc/<pid>/exeresolves toelectron(catches all main processes) - Cmdline match — matches known app identifiers against renderer threads (e.g.
--type=renderer code)
| Category | Apps included |
|---|---|
| Messengers | Slack, Discord, Teams, Zoom, Element, Mattermost, Rocket.Chat, Signal, Telegram, Wavebox, Threema, Zulip, Caprine, Francium/X, Bluesky |
| Code editors | VS Code, VSCodium, Cursor, WindSurf, Zed, GoLand, RubyMine, Atom, Fleet |
| Design | Figma, Penpot, Excalidraw, Canva, Inkscape Web, Lunacy, Affinity Designer |
| Productivity | Notion, Evernote, Obsidian, Logseq, Joplin, Roam Research, Craft, Bear Notes |
| Office | LibreOffice, OnlyOffice, WPS Office, Google Docs Offline |
| Thunderbird, Outlook, Tutanota, ProtonMail Bridge, BlueMail, Canary Mail | |
| Media players | Spotify, VLC, Audacity, Plex, Roon, Tidal, Deezer, BandLab |
| File managers | Dropbox, MegaSync, Syncthing Tray, Nextcloud Desktop, PCloud Drive |
| Dev tools | Postman, Insomnia, TablePlus, DBeaver, Hoppscotch, Beekeeper Studio |
| Browsers | Brave, Vivaldi, Arc, Opera GX, Waterfox, Pale Moon |
| Task managers | Todoist, Sunsama, Reclaim.ai, Motion AI, Google Calendar |
| Utilities | BalenaEtcher, NordVPN, Docker Desktop helper, ExpressVPN |
To add a custom app identifier, append to any category variable in ~/.local/bin/electron-bucket.sh:
# Before the declare -A TRACKED line:
MY_APPS="my-custom-app|another-tool"Then update the combined pattern loop (around the for cg_var in ... block) to include your new variable.
systemctl --user status electron-shield
journalctl --user -u electron-shield -f # live tail
journalctl --user -u electron-shield --since today # today's entriescat /sys/fs/cgroup/user-1000.slice/user@1000.service/electron-shield/cpu.max
cat /sys/fs/cgroup/user-1000.slice/user@1000.service/electron-shield/memory.max
cat /sys/fs/cgroup/user-1000.slice/user@1000.service/electron-shield/pids.maxls /sys/fs/cgroup/user-1000.slice/user@1000.service/electron-shield/ | grep -E '^user-'
# Each sub-cgroup entry corresponds to a process moved into the cgroup.
ps --no-headers -o pid,comm -p $(cat /sys/fs/cgroup/user-1000.slice/user@1000.service/electron-shield/cgroup.procs 2>/dev/null | tr '\n' ' ')systemctl --user stop electron-shield
systemctl --user disable electron-shield # optional: prevent restart on bootcurl -fsSL https://raw.githubusercontent.com/lleqsnoom/electron-shield/main/uninstall.sh | bashOr manually:
systemctl --user stop electron-shield
systemctl --user disable electron-shield
rm ~/.config/systemd/user/electron-shield.service
rm ~/.local/bin/electron-bucket.sh
rm ~/.config/electron-shield.conf
systemctl --user daemon-reload
# Clean up cgroup: sudo rm -rf /sys/fs/cgroup/user-1000.slice/user@1000.service/electron-shield- The systemd user service launches
electron-bucket.shin a loop every 5 seconds - On each iteration, the script scans
/proc/[pid]/exefor Electron binaries and matches renderer threads against known app identifiers - Detected processes are moved into a cgroup at
/sys/fs/cgroup/user-1000.slice/user@1000.service/electron-shield/ - The cgroup's
cpu.max,memory.max, andpids.maxenforce hard limits via cgroup v2 kernel controllers - User-level systemd services automatically get
subtree_controlrights, so no root is needed
- Linux with cgroup v2 (most distros since ~2019)
- systemd user session running
- Bash 4+ (for associative arrays and extglob)
- Only works in cgroup v2 systems (not v1 without
systemd-cgtopconversion) - Limits apply to the cgroup, not individual apps — all Electron processes share the pool
- Some Electron forks (e.g. custom Chromium-based apps) may not match detection patterns — add manually via the category variables
- PID limit is shared across all managed Electron processes, not per-app
Service won't start: Check systemctl --user status electron-shield and journalctl --user -u electron-shield. Common cause: cgroup v2 not mounted (cat /proc/filesystems | grep cgroup2).
Processes not being caught: Verify your Electron apps appear in /sys/fs/cgroup/user-1000.slice/user@1000.service/electron-shield/cgroup.procs after the daemon starts. If missing, check journalctl --user -u electron-shield -f for detection logs.
Permission denied writing cgroup: Ensure you're running a systemd user session (systemctl --user status should work). User services get subtree_control automatically — if not, your distro may need UserAllowArchitecture=auto in /etc/systemd/system.conf.
MIT