Skip to main content
ansicode

DECSET 1049 — Alternate screen buffer

Switch to a separate screen buffer (like vim/less do on launch).

Byte forms

Every common string-literal form so you can paste-and-search either direction.

\\x1b[\x1b[?1049h (enter) \x1b[?1049l (leave)
\\033[\033[?1049h / \033[?1049l
\\e[\e[?1049h / \e[?1049l
ESC [ESC [ ? 1 0 4 9 h / l
hex1b 5b 3f 31 30 34 39 68 / 6c

Description

DEC private mode 1049 is the canonical 'enter full-screen app' sequence. On enter (\x1b[?1049h), the terminal performs three actions atomically: saves the cursor position + attributes (equivalent to DECSC \x1b7), switches to a fresh alt screen buffer (no scrollback), and clears that alt buffer. On leave (\x1b[?1049l), the original primary buffer is repainted and the cursor is restored — this is what lets you q out of vim / less / htop and find your shell prompt exactly where you left it, with the alt buffer's content discarded. Older modes 47 (\x1b[?47h) and 1047 (\x1b[?1047h) do almost the same thing but without the cursor save/restore (47) or without the clear-on-enter (1047) — modern TUIs should always use 1049 unless targeting an emulator that pre-dates it (xterm patch #251, 2010). Specification lives in xterm-ctlseqs under 'Private Modes'.

Alt-screen is the most fragile mode pair in terminal programming because the entire 'TUI cleanup contract' hinges on the matching \x1b[?1049l actually running. Three live pitfalls cluster here. (1) Newline trap: the cursor often ends up on the wrong row after leaving — DECSET 1049 restores the saved cursor, but the last visible line your program wrote inside alt-screen usually lacked a trailing newline, so the restore lands the cursor one row too high (see alt-screen-newline); fix by emitting \r\n or DECRC (\x1b8) just before \x1b[?1049l. (2) CRLF trap inside alt-screen: plain \n (LF, 0x0A) is 'down one row' without carriage return — direct-write programs that emit \n between status lines see stair-stepped output (line 2 starts where line 1 ended). Emit \r\n (or set IXON / cooked-mode line discipline) — see crlf-under-alt-screen. (3) The broader cleanup-on-crash family: if your TUI also emits \x1b[?25l (hide cursor), \x1b[?1h\x1b= (smkx — app-keypad mode), \x1b[?2004h (bracketed paste) or \x1b[?1000h\x1b[?1006h (mouse tracking) on enter, every one of those needs its matching un-set in the same cleanup block that exits alt-screen — otherwise the user's post-crash shell has invisible cursor / arrow keys producing OA / pastes wrapped in \x1b[200~ markers. See stuck-cursor-hidden, stuck-app-mode, stuck-bracketed-paste. Coverage caveat: cmd.exe (legacy conhost without ConPTY) lists as 'partial' — early Win10 conhost dropped 1049 entirely; Win10 1709+ via ConPTY honours it.

Disable with \x1b[?1049l — and the leave path must be reachable from EVERY exit, including SIGINT, SIGTERM, SIGQUIT, panics, segfaults. In Go: defer fmt.Print("\x1b[?1049l\x1b[?25h") plus a signal.Notify handler. In Python: atexit.register(...) plus signal.signal(signal.SIGINT, ...). In Rust crossterm: LeaveAlternateScreen in a Drop impl on a guard struct so unwinding handles it. Prefer a real TUI library (crossterm, blessed, textual, bubbletea, ratatui) over hand-rolling — they centralise the cleanup contract and have already debugged the cases above. Related private modes that almost always travel with 1049: cursor-visibility (\x1b[?25l/\x1b[?25h) for hidden cursor during redraws, dec-bracketed-paste (\x1b[?2004h) to discriminate paste vs typing, and cursor-save-restore (\x1b7/\x1b8) for finer position bookkeeping inside the alt buffer.

Spec citation: xterm-ctlseqs (Private modes)

Examples

bash
printf '\033[?1049h'; sleep 2; printf '\033[?1049l'
python
import sys, time\nsys.stdout.write('\x1b[?1049h'); sys.stdout.flush(); time.sleep(2); sys.stdout.write('\x1b[?1049l')
go
fmt.Print("\x1b[?1049h"); time.Sleep(2*time.Second); fmt.Print("\x1b[?1049l")
javascript
process.stdout.write('\x1b[?1049h'); setTimeout(() => process.stdout.write('\x1b[?1049l'), 2000)
c
printf("\x1b[?1049h"); sleep(2); printf("\x1b[?1049l");

Used in

Real-world tools that emit this sequence — anchors the bytes to commands you've already used.

  • vim, neovim, nanoenter alt-screen on open so the editor session doesn't pollute scrollback
  • less, more, manalt-screen on entry, restore on `q` — leaving the pager returns to the prior terminal state
  • htop, top, btop, glances
  • tmux, GNU screen
  • mc (Midnight Commander), ranger

Frequently asked

Short answers to the questions developers actually search for this sequence.

Why does my scrollback disappear when I open less or vim?
They switched into the alternate screen buffer (\x1b[?1049h) — a separate scrollback-less page that gets cleared on entry and discarded on exit. The original screen contents come back the moment the program emits \x1b[?1049l. This is the intended behaviour: alt-screen is for full-screen TUIs that don't want their output mixed into the user's history.
Should I use ?1049 or ?1047 for alt-screen?
?1049 for almost everything new. It atomically saves cursor + clears + enters alt-screen on entry, and restores cursor + exits on leave — one round trip, no save/restore plumbing. ?1047 is the older xterm form that only switches buffers without the save/clear, leaving you to drive DECSC / DECRC manually. New code should pick ?1049 unless you specifically want the old semantics.
Why is my cursor in the wrong row after I exit alt-screen?
\x1b[?1049l restores the cursor to the column / row it was on before alt-screen entry, then prints the next byte on that row — so if your final shell prompt expected to start on a fresh line, it ends up overwriting whatever was there. Emit an explicit \r\n (or \n after CRLF translation) right after exit to land on a fresh line. See the alt-screen-newline pitfall.

Terminal support

xterm
yes
Linux console (fbcon)
yes
macOS Terminal.app
yes
iTerm2
yes
Windows Terminal
yes
cmd.exe / ConPTY
partial
kitty
yes
alacritty
yes
WezTerm
yes
Ghostty
yes
GNOME Terminal
yes
Konsole
yes
tmux
yes
GNU screen
yes

Related sequences

In the family cookbook

DEC cookbook · 1. The `?` prefix — DECSET vs SM