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[?1049h (enter) \x1b[?1049l (leave)\033[?1049h / \033[?1049l\e[?1049h / \e[?1049lESC [ ? 1 0 4 9 h / l1b 5b 3f 31 30 34 39 68 / 6cDescription
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
printf '\033[?1049h'; sleep 2; printf '\033[?1049l'import sys, time\nsys.stdout.write('\x1b[?1049h'); sys.stdout.flush(); time.sleep(2); sys.stdout.write('\x1b[?1049l')fmt.Print("\x1b[?1049h"); time.Sleep(2*time.Second); fmt.Print("\x1b[?1049l")process.stdout.write('\x1b[?1049h'); setTimeout(() => process.stdout.write('\x1b[?1049l'), 2000)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
lessorvim? - 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
?1049or?1047for alt-screen? ?1049for 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.?1047is the older xterm form that only switches buffers without the save/clear, leaving you to drive DECSC / DECRC manually. New code should pick?1049unless you specifically want the old semantics.- Why is my cursor in the wrong row after I exit alt-screen?
\x1b[?1049lrestores 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\nafter CRLF translation) right after exit to land on a fresh line. See thealt-screen-newlinepitfall.
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
| xterm | Linux console (fbcon) | macOS Terminal.app | iTerm2 | Windows Terminal | cmd.exe / ConPTY | kitty | alacritty | WezTerm | Ghostty | GNOME Terminal | Konsole | tmux | GNU screen |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| yes | yes | yes | yes | yes | partial | yes | yes | yes | yes | yes | yes | yes | yes |