惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

N
Netflix TechBlog - Medium
博客园 - 聂微东
M
MIT News - Artificial intelligence
The Hacker News
The Hacker News
AI
AI
Hacker News: Ask HN
Hacker News: Ask HN
Cloudbric
Cloudbric
GbyAI
GbyAI
B
Blog RSS Feed
S
Secure Thoughts
O
OpenAI News
S
Schneier on Security
Latest news
Latest news
C
Check Point Blog
Know Your Adversary
Know Your Adversary
T
Tenable Blog
J
Java Code Geeks
The Cloudflare Blog
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
WordPress大学
WordPress大学
P
Proofpoint News Feed
雷峰网
雷峰网
Engineering at Meta
Engineering at Meta
C
Cyber Attacks, Cyber Crime and Cyber Security
Cisco Talos Blog
Cisco Talos Blog
H
Hacker News: Front Page
www.infosecurity-magazine.com
www.infosecurity-magazine.com
美团技术团队
博客园 - 司徒正美
Security Latest
Security Latest
Forbes - Security
Forbes - Security
W
WeLiveSecurity
Webroot Blog
Webroot Blog
Last Week in AI
Last Week in AI
L
LINUX DO - 热门话题
Google DeepMind News
Google DeepMind News
Martin Fowler
Martin Fowler
月光博客
月光博客
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Help Net Security
Help Net Security
H
Help Net Security
Recent Commits to openclaw:main
Recent Commits to openclaw:main
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
U
Unit 42
V2EX - 技术
V2EX - 技术
阮一峰的网络日志
阮一峰的网络日志
SecWiki News
SecWiki News
T
Troy Hunt's Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
T
The Exploit Database - CXSecurity.com

Lobsters

CIFSwitch: a non-universal Linux local root vulnerability RIPE NCC session fixation: poaching logins with an Atlas probe GNOME 2.20 but its Web Components Agentic Search for Context Engineering – Leonie Monigatti Garnix is shutting down [not OC] akashina.tngl.sh/jjc Concerning Emacs (and Jazz) Nitpicking the shell history scene in ‘Tron: Legacy’ What's cooking on SourceHut? Q2 2026 The tenth OpenPGP email summit Package managers that package package managers Clojure on Fennel part three: parsing WordPress at 23 Finding Miscompiles for Fun, Not Profit GitHub - creusot-rs/creusot: Creusot helps you prove your Rust code is correct. Announcing Rust 1.96.0 | Rust Blog A Love Letter to Neovim sqlite AGENTS.md Am I a Bad Friend? CSS vs. JavaScript • Josh W. Comeau Erlang Ecosystem Foundation - Supporting the BEAM community A brief note about slot access cost in Common Lisp Keyboard latency probe Rethinking the GNOME clipboard issues Back to the Building Blocks’ Building Blocks Tech Notes: Theseus: translating win32 to wasm Fast is better than slow Content-addressed Rust builds (or, what kache actually caches) Intent to Prototype: Embedding API Canada’s Bill C-22 and the security cost of collecting more data 5 PostgreSQL locking behaviors that trip people up okmij.org Stop advertising in your commits! | AksDev GitHub - mplsllc/macsurf: A modern web browser for Classic Mac OS 9 PowerPC. Real CSS3, ES5 JavaScript, native HTTPS — built with CodeWarrior on the Carbon API. Introducing DoomBench - Can Your Data Stack Run DOOM? What are some of your favourite developer tools? Building a Scalable Ingestion Pipeline with Temporal (Part 1) Converting shallow Git bundles into normal repositories Are you a member of any professional associations? What is a harmonic? An interactive comic about additive synthesis How Virtual Tables Work in the Itanium C++ ABI Using SwiftUI to Build a Mac-assed App in 2026 Rust (and Slint) on a jailbroken Kindle. ~jack/lambda-on-lambda - Serverless Haskell on AWS - sourcehut git Human proof for FOSS contributions Extremely simple internet radio controlled via IRC Announcing BABLR Splitting Konsole views from Helix to run tools | AksDev GitHub - yugr/rust-slides Serving files over HTTP three ways: synchronous, epoll, and io_uring update docs with information about building with build.py (#979) · astral-sh/python-build-standalone@c9c40c5 A Simple Makefile Tutorial On C extensions, portability, and alternative compilers Switching to Colemak | Pedro Alves Just How Bad Was The Intel IAPX432? Nix's Substituter List Is Not a Routing Table Accelerating copy_if using SIMD Lambda on Lambda: Serverless Haskell on AWS | Blog Announcing feed-repeat v1.0 Scaling Akvorado BMP RIB with sharding EYG news: A host of CLI improvements, new guides and new effects The social contract of writing JS Crossword C array types are weird; and related topics Flatpak will depend on systemd – OSnews Migrating from Go to Rust | corrode Rust Consulting A portentous reunion Vivado Licensing Options How my minimal, memory-safe Go rsync steers clear of vulnerabilities the entropy layer of a wavelet codec, on its own GitHub - nferhat/fht-compositor: A dynamic tiling Wayland compositor. Debian SE Linux and PinTheft Does bulk memmove speed up std::remove_if? (No.) 声明式部分更新 | Blog | Chrome for Developers Fully in-browser container builds Dianne Skoll's Web Site - Remind The Architecture of Open Source Applications (Volume 1)Berkeley DB Pardon MIE? - ironPeak Blog “Long-Term Support” doesn’t mean what you think Jira IS Turing-Complete May I recommend thinking of Emacs as your Fortress of Solitude hershey Floodgap Gopher-HTTP gateway gopher://thelambdalab.xyz/1cuneiforth/ HP QuickWeb, Singular And Pointless That one time I used Go panics for flow control A new suite of modern tools coming for editing and publishing RFCs From the Tabletop… The Digital Antiquarian Building a Host-Tuned GCC to Make GCC Compile Faster Are we self-sovereign PKI yet? Claw Patrol: an open-source security firewall for agents | Deno Revised^7 Report on Scheme, Large: Procedural Fascicle Draft is now public A Network Allow-List Won't Stop Exfiltration — André Graf From AFSK to Goertzel – µArt.cz Software For My New Home Server Introducing Neptune: Direct3D virtualization for QEMU AI Agent Bankrupted Their Operator While Trying to Scan DN42 - Lan Tian @ Blog mimalloc: A new, high-performance, scalable memory allocator for the modern era Making wl_shm fast The Soul of Maintaining a New Machine - Third Draft | Books in Progress What is Git made of?
Life is too short for a slow terminal
Mijndert Stuij · 2026-06-06 · via Lobsters

Practically all of my work happens inside a terminal. Git, kubectl, tmux, ssh'ing into a server, open practically the entire day. Something I use that much has to be fast. Any lag in opening a new tab, typing a character or hitting tab for a completion is something I feel hundreds of times a day. It's death by a thousand cuts.

My shell starts in about 30 milliseconds:

$ for i in {1..5}; do /usr/bin/time zsh -i -c exit; done
0.03 real  0.02 user  0.01 sys
0.03 real  0.02 user  0.01 sys
...

That's a fully loaded interactive shell with completions, syntax highlighting, autosuggestions, fzf and direnv, in less time than a single frame at 30fps. A new tab is instant. There was never some big optimization project behind this either; I've just always kept my shell minimal and fast and over the years that turned into a habit. Here's how I go about it, and all of it can be found in my dotfiles.

No framework

The single biggest win is what's not there: no oh-my-zsh, no prezto or plugin manager. I've honestly never understood the appeal of these frameworks. People install oh-my-zsh with its hundreds of plugins and themes, end up using maybe 5% of what it offers, and then pay (with their time and compute resources) for the other 95% every single time they open a shell. And plugin managers add their own overhead on top of that.

I use exactly three plugins, git-cloned once by my install script and sourced from .zshrc:

source ~/.zsh/fzf-tab/fzf-tab.plugin.zsh
source ~/.zsh/zsh-autosuggestions/zsh-autosuggestions.zsh
source ~/.zsh/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh

There's no plugin manager doing dependency resolution at startup, and a source of a file that's already on disk is practically free.

Caching completions

compinit is one of the most expensive things in a typical .zshrc. By default it does a security audit of every completion file, every single time you open a shell. The fix is to only do the full run if the cache (.zcompdump) is older than 24 hours, and otherwise skip the check with -C:

autoload -Uz compinit
if [[ -n ~/.zcompdump(#qNmh-24) ]]; then
  compinit -C
else
  compinit
fi

That glob qualifier (#qNmh-24) reads as "exists and was modified within the last 24 hours". So one full compinit per day, and cached reads the rest of the time.

Lazy-loading

nvm is probably the most notorious shell startup killer out there; sourcing it eagerly can easily add half a second. But I don't need nvm in every shell, I need it when I type nvm. So I wrap it in a function that replaces itself on first use:

export NVM_DIR="$HOME/.nvm"
nvm() {
  unset -f nvm
  [ -s "/opt/homebrew/opt/nvm/nvm.sh" ] && \. "/opt/homebrew/opt/nvm/nvm.sh" --no-use
  [ -s "/opt/homebrew/opt/nvm/etc/bash_completion.d/nvm" ] && \. "/opt/homebrew/opt/nvm/etc/bash_completion.d/nvm"
  nvm "$@"
}

The first nvm call deletes the stub, sources the real thing (with --no-use so it doesn't resolve a node version either), and forwards the arguments.

Same idea for kubectl completions, which shell out to the kubectl binary to generate the completion script. I only load them after the first time I actually run kubectl:

kubectl() {
    command kubectl "$@"
    local ret=$?
    if [[ -z $KUBECTL_COMPLETE ]]; then
        source <(command kubectl completion zsh)
        KUBECTL_COMPLETE=1
    fi
    return $ret
}

This pattern works for a lot of things: anything that tells you to put eval "$(tool init zsh)" in your .zshrc is a candidate for lazy loading, because each of those forks a process and evaluates its output at startup. I keep direnv and fzf eager because they're fast and I use them constantly. Be strict about what you actually use a lot.

A non-blocking prompt

A prompt that runs git status synchronously will lag in any decently sized repo. That's the kind of lag you feel on every single Enter press, which is arguably worse than a slow startup. I use pure, which renders the prompt immediately and fills in the git info asynchronously when it's ready. I briefly tried replacing it with zsh's built-in vcs_info, but pure's async behavior is just... better. You can do async git status in your own prompt as well, but pure wraps it rather nicely for my use-case.

The terminal itself

Shell startup is only half the story, because the emulator adds its own input latency. I use Ghostty, which is GPU-accelerated and native, and my config is just seven lines long. Combined with a tmux new -A -s main alias (t), a fresh terminal window drops me right back into my existing session.

Measuring your own shell performance

You don't have to take my word for any of this, you can measure where the time goes in your own terminal. There are three kinds of lag to look for: startup time, prompt lag, and input latency.

Run this a few times (the first run is always slower because of cold caches):

time zsh -i -c exit

I think anything under 100ms is fine, and under 50ms is great. If you're seeing 500ms or more you have some work to do.

For proper statistics, use hyperfine:

hyperfine --warmup 3 'zsh -i -c exit'

Zsh also ships with a profiler. Put this at the very top of your .zshrc:

zmodload zsh/zprof

and this at the very bottom:

zprof

Open a new shell and you get a sorted table of exactly where the time went. The top entries are usually compinit, an nvm.sh source, or some eval "$(...)". Fix the top one, re-run, repeat. Remove both lines when you're done.

If zprof isn't granular enough, you can trace the whole startup with timestamps:

zsh -ixc exit 2>&1 | ts -i '%.s' | sort -rn | head -20

Or set PS4='+%D{%s.%6.}: ' and run zsh -ixc exit 2> startup.log, then look for the big jumps between lines.

Startup can be fast while every prompt redraw is slow. cd into your biggest git repo and press Enter; if there's a delay before the next prompt appears, your prompt is doing synchronous work slowing it down. You can either switch to using an async prompt, or opt to strip out the Git functionality.

Wrapping up

Most of these optimizations are about leaving stuff out. It's about being intentional and only adding things you're going to use. Every one of the dozens of sessions I open per day is instant, and my terminal feels like an extension of my brain instead of an application I'm waiting on. For a tool I use the entire day that's non-negotiable for me.

All of the above lives in my dotfiles repo if you want to steal anything.