Emacs terminal buffers like eat, vterm, ghostel, term, and ansi-term can become slow when processing large volumes of standard output. Watching Emacs freeze while a build script dumps thousands of lines is frustrating, but terminal latency is not an unavoidable cost of living inside Emacs. Applying a few targeted configuration changes will eliminate scroll lag and restore immediate responsiveness. This article provides a configuration that speed up terminal buffers.
Before we begin, please consider sharing this article on your website, blog, Mastodon, Reddit, X, LinkedIn, Hacker News, or other social media platforms. Sharing it will help other Emacs users discover how to improve the performance of their terminal emulators.
Complete configuration for high-performance terminal buffers
The following Elisp code speeds up Emacs terminals by applying settings and disabling minor modes that are unnecessary in terminal buffers:
;; Description: Speed up Emacs terminals (vterm, eat, ghostel, term, and ansi-term)
;; Author: James Cherti
;; License: MIT
;; URL: https://www.jamescherti.com/emacs-terminal-performance-vterm-eat-ansi-term-ghostel/
(setq vterm-timer-delay 0.01)
(setq ghostel-timer-delay 0.01)
(setq eat-minimum-latency 0.01)
(setq eat-maximum-latency 0.05)
(setq vterm-max-scrollback 500)
(setq ghostel-max-scrollback (* 1024 1024))
(setq eat-term-scrollback-size (* 64 1024))
(setq eat-enable-shell-prompt-annotation nil)
;; Uncomment -DUSE_SYSTEM_LIBVTERM if you prefer system libvterm
(setq vterm-module-cmake-args
(concat "-DCMAKE_C_FLAGS='-O3 -march=native -mtune=native' "
"-DCMAKE_SHARED_LINKER_FLAGS='-Wl,-O2 -Wl,--as-needed' "
;; "-DUSE_SYSTEM_LIBVTERM=yes"
))
(defun my-speed-up-terminal-buffer ()
"Reduce unnecessary Emacs features in terminal buffers."
(let ((ghostel-buffer (derived-mode-p 'ghostel-mode)))
(setq-local font-lock-defaults '(nil t))
(setq-local fast-but-imprecise-scrolling t)
(setq-local redisplay-skip-fontification-on-input t)
(setq-local scroll-conservatively most-positive-fixnum)
(setq-local hscroll-margin 0)
(setq-local scroll-margin 0)
(setq-local scroll-step 0)
(setq-local hscroll-step 0)
(setq-local auto-hscroll-mode nil)
;; Uncomment to disable scroll bars to save redisplay cycles
;; (setq-local vertical-scroll-bar nil)
;; (setq-local horizontal-scroll-bar nil)
(setq-local truncate-lines t)
(setq-local nobreak-char-display nil)
(setq-local bidi-paragraph-direction 'left-to-right)
(setq-local bidi-inhibit-bpa t)
;; Ghostel coordinates row height calculations via ghostel-line-spacing
(unless ghostel-buffer
(setq-local line-spacing 0)
(setq-local mode-line-format nil))
(setq-local echo-keystrokes 0)
(setq-local process-adaptive-read-buffering nil)
(let ((output-max (* 1024 1024)))
(when (< read-process-output-max output-max)
(setq-local read-process-output-max output-max)))
(buffer-disable-undo)
;; Evil users
(remove-hook 'pre-command-hook 'evil--jump-hook t)
(remove-hook 'post-command-hook 'evil--jump-handle-buffer-crossing t)
;; Disable modes
(let ((inhibit-redisplay t)
(inhibit-message t)
(modes '(electric-pair-local-mode
electric-indent-local-mode
display-line-numbers-mode
display-fill-column-indicator-mode
hl-line-mode
show-paren-local-mode
flymake-mode
;; Third-party packages
;; NOTE: Add more modes here
flycheck-mode
evil-surround-mode
evil-snipe-local-mode
yas-minor-mode
company-mode
corfu-mode)))
;; ghostel-comint, ghostel-compile, and ghostel-links register a function
;; in eldoc-documentation-functions to display target URLs and file under
;; point.
;;
;; Ghostel uses auto-composition-mode in the sync tty composition
;; function.
(unless ghostel-buffer
(push 'eldoc-mode modes)
(push 'auto-composition-mode modes))
(dolist (mode modes)
(when (and (boundp mode)
(symbol-value mode)
(fboundp mode))
(ignore-errors
(funcall mode -1)))))))
(add-hook 'term-mode-hook 'my-speed-up-terminal-buffer t)
(add-hook 'vterm-mode-hook 'my-speed-up-terminal-buffer t)
(add-hook 'eat-mode-hook 'my-speed-up-terminal-buffer t)
(add-hook 'ghostel-mode-hook 'my-speed-up-terminal-buffer t)
Note: Some of the setq-local settings in this function, excluding the settings that disable minor modes, are provided by modern terminal emulators such as vterm, Eat, and Ghostel. However, each emulator exposes a different set of variables, so this function sets the relevant settings for all supported emulators in one place for consistency and simplicity.
Why these settings help
The code snippet above reduces display, fontification, undo, and minor-mode performance cost in terminal buffers.
Terminal-specific configuration
(setq vterm-timer-delay 0.01)
(setq ghostel-timer-delay 0.01)
(setq eat-minimum-latency 0.01)
(setq eat-maximum-latency 0.05)
(setq vterm-max-scrollback 500)
(setq ghostel-max-scrollback (* 1024 1024))
(setq eat-term-scrollback-size (* 64 1024))
(setq eat-enable-shell-prompt-annotation nil)
;; Uncomment -DUSE_SYSTEM_LIBVTERM if you prefer system libvterm
(setq vterm-module-cmake-args
(concat "-DCMAKE_C_FLAGS='-O3 -march=native -mtune=native' "
"-DCMAKE_SHARED_LINKER_FLAGS='-Wl,-O2 -Wl,--as-needed' "
;; "-DUSE_SYSTEM_LIBVTERM=yes"
))
vterm-timer-delay,eat-minimum-latency,eat-maximum-latency, andghostel-timer-delay: These control how terminal output is batched before redisplay. Lowering these values reduces the delay before output appears, at the cost of more frequent redraws during heavy output. These settings are worth it because they make terminal emulator feel less sluggish.eat-enable-shell-prompt-annotation: Disabling shell prompt annotations avoids the processing associated with maintaining them.vterm-max-scrollback,eat-term-scrollback-size, andghostel-max-scrollback: These set the amount of history retained by each emulator.ghostel-max-scrollbackis measured in bytes,vterm-max-scrollbackin lines, andeat-term-scrollback-sizein characters.vterm-module-cmake-args: Passes additional CMake arguments when compiling the vterm C module. The-O3,-march=native, and-mtune=nativeflags request aggressive compiler optimization and CPU-specific tuning. (Building with-march=nativeoptimizes the binary specifically for your current CPU architecture. You can only run this module on machines with the same CPU architecture.)
Line rendering, wrapping, and UI
(setq-local truncate-lines t)
(setq-local nobreak-char-display nil)
(setq-local bidi-paragraph-direction 'left-to-right)
(setq-local bidi-inhibit-bpa t)
;; Ghostel coordinates row height calculations via ghostel-line-spacing
(unless ghostel-buffer
(setq-local line-spacing 0)
(setq-local mode-line-format nil))
(setq-local echo-keystrokes 0)
truncate-lines: Setting this totstops long lines from wrapping. This bypasses expensive line-wrapping calculations, allowing the display engine to render text sequentially.nobreak-char-display: Emacs highlights non-breaking spaces and soft hyphens by default. Setting this tonilstops Emacs from overlaying highlight boxes on top of terminal output.line-spacing: TUI applications use box-drawing characters to create borders. Setting this to0removes vertical pixel gaps between lines, ensuring pixel-perfect vertical alignment for TUI borders and progress bars.bidi-paragraph-directionandbidi-inhibit-bpa: Emacs scans text by default to determine if it should be rendered right-to-left. Settingbidi-paragraph-directionto'left-to-rightandbidi-inhibit-bpatotforces left-to-right rendering. This bypasses expensive text scanning. Right-to-left languages will render incorrectly in the shell.echo-keystrokes: Setting this to0disables the echoing of unfinished keystrokes in the minibuffer.mode-line-format: Setting this tonilhides the mode-line. This stops Emacs from constantly re-evaluating mode-line functions (which check Git status or active modes) on terminal buffers.
Accelerating display and scrolling
(setq-local fast-but-imprecise-scrolling t)
(setq-local redisplay-skip-fontification-on-input t)
(setq-local scroll-conservatively most-positive-fixnum)
(setq-local hscroll-margin 0)
(setq-local scroll-margin 0)
(setq-local scroll-step 0)
(setq-local hscroll-step 0)
(setq-local auto-hscroll-mode nil)
;; Uncomment to disable scroll bars to save redisplay cycles
;; (setq-local vertical-scroll-bar nil)
;; (setq-local horizontal-scroll-bar nil)
fast-but-imprecise-scrolling: Accelerates scrolling by allowing Emacs to skip fontification during rapid scroll events.redisplay-skip-fontification-on-input: Causes the redisplay engine to skip thefontification_functionspass when pending input exists. This improves responsiveness when typing.scroll-conservatively: Setting this variable tomost-positive-fixnummakes Emacs scrolls only enough to bring point into view rather than recentering.hscroll-marginandscroll-margin: Define the horizontal and vertical padding around point before scrolling occurs. Setting them to0disables this padding, preventing the display engine from performing recentering calculations when point nears the window edge.scroll-stepandhscroll-step: Setting these to0means the normal centering behavior.auto-hscroll-mode: Disallows automatic horizontal scrolling of windows.vertical-scroll-barandhorizontal-scroll-bar: Disables the scroll bars. Every time new text is inserted, the redisplay engine recalculates the size and position of the scroll bar thumb based on the new buffer size. Disabling scroll bars removes the scroll-bar-related redisplay and UI work for the terminal buffer.
Process I/O and buffering
(setq-local process-adaptive-read-buffering nil)
(let ((output-max (* 1024 1024)))
(when (< read-process-output-max output-max)
(setq-local read-process-output-max output-max)))
Increasing read-process-output-max allows Emacs to read up to (* 1024 1024) amounts of output in a single system call. However, a larger chunk size alone is not enough because the default process-adaptive-read-buffering algorithm will still inject micro-sleeps, assuming rapid bursts of escape sequences are caused by a background process that needs throttling.
Ensuring process-adaptive-read-buffering is disabled forces the event loop to stop second-guessing the data stream and immediately consume those chunks as fast as the operating system provides them. (Adaptive read buffering is disabled by default. This is included in case the global value has been modified in your Emacs configuration.)
Disabling syntactic fontification
(setq-local font-lock-defaults '(nil t))
Setting font-lock-defaults to (nil t) turns off automatic fontification for the buffer. The first element specifies that there are no font-lock keywords, while the second sets font-lock-keywords-only, which prevents syntactic fontification.
This is useful for terminal buffers because terminal emulators do not generally need Emacs to apply programming-language fontification to their contents. Terminal applications manage their own colors through terminal escape sequences.
Disabling undo history
(buffer-disable-undo)
Disables recording undo data for the buffer.
Managing Evil mode hooks (Evil-mode users)
(remove-hook 'pre-command-hook 'evil--jump-hook t)
(remove-hook 'post-command-hook 'evil--jump-handle-buffer-crossing t)
evil--jump-hookandevil--jump-handle-buffer-crossing: These hooks are used by Evil mode to calculate and store jump list entries on every command. Removing them bypasses the computation and storage of jump list entries for every single command executed in the terminal. The downside is that Evil mode users cannot useC-oorC-ito return to a previous cursor position in terminal buffers.
Disabling intrusive minor modes
(let ((inhibit-redisplay t)
(inhibit-message t)
(modes '(electric-pair-local-mode
electric-indent-local-mode
display-line-numbers-mode
display-fill-column-indicator-mode
hl-line-mode
show-paren-local-mode
flymake-mode
;; Third-party packages
;; NOTE: Add more modes here
flycheck-mode
evil-surround-mode
evil-snipe-local-mode
yas-minor-mode
company-mode
corfu-mode)))
;; ghostel-comint, ghostel-compile, and ghostel-links register a function
;; in eldoc-documentation-functions to display target URLs and file under
;; point.
;;
;; Ghostel uses auto-composition-mode in the sync tty composition
;; function.
(unless ghostel-buffer
(push 'eldoc-mode modes)
(push 'auto-composition-mode modes))
(dolist (mode modes)
(when (and (boundp mode)
(symbol-value mode)
(fboundp mode))
(ignore-errors
(funcall mode -1)))))
yas-minor-mode,evil-snipe-local-mode,evil-surround-mode: These modes intercept keystrokes for snippets or character searches. Disabling them bypasses extra keymap lookups and event loop interceptions, reducing latency between keystroke and terminal input.hl-line-mode,display-line-numbers-mode: These modes alter the visual representation of lines. Disabling them prevents the display engine from removing and recreating overlays on every cursor movement or calculating margin widths for every visible line.electric-pair-local-mode,electric-indent-local-mode,show-paren-local-mode,auto-composition-mode: These modes analyze syntax to insert quotes, indent lines, or highlight brackets. Disabling them stops Emacs from running complex regex, syntax table lookups, and text-shaping on every typed character or newline, which speeds up text rendering.company-mode,corfu-mode,flymake-mode,flycheck-mode,eldoc-mode: These modes manage completion, linting, and documentation lookups. Disabling these modes removes their associated hooks, redisplay work, buffer analysis, completion, diagnostics, or other processing from terminal buffers.