Backend engineeringThe GNU nano editor12 modules, keys at hand
Nano
Toolbox
Every shortcut you need to edit config files and scripts on any server without leaving the terminal: save and quit, move fast, cut and paste, search and replace, then make nano your own with .nanorc. Press Run on any session to replay it.
Open, save, quit
The three things to learn before anything else. Once you can get out of nano with your work saved, the rest is speed.
nano shows its own key notation: ^ is Ctrl and M- is Alt. The two lines at the bottom of the screen list the most common shortcuts, so you are never stuck guessing.
nano notes.txt # open, or create if missing
nano +42 app.js # open at line 42
nano -v /etc/hosts # view only, no edits
^O # write out: Enter keeps the name
^S # save straight away, no prompt
^X # exit; asks to save if changed
^G # help: every key, ^X closes it
^X with unsaved changes asks first. Press Y to save, N to throw the changes away, or ^C to go back to editing.
# a recorded session, replayed when you press Run nano notes.txt # type two lines, then save ^O File Name to Write: notes.txt Enter [ Wrote 2 lines ] ^X cat notes.txt rotate db password on friday bump node to 22 on staging
Worth remembering
| Keys | Does |
|---|---|
^O | Save, asking for the file name |
^S | Save without a prompt |
^X | Exit, offering to save first |
^G | Show the help screen |
^C at a prompt | Cancel the prompt |
Move around
Arrow keys work, but long config files need bigger jumps: by word, by page, to a line number, or to either end of the file.
Go to line is the jump you will use most, because error messages name a line. Press ^_ (or ^/), type the number, and press Enter. Add a comma and a column to land on the exact character.
Start and end of the line.
See the exampleOne screen up or down.
See the exampleGo to line 42, or 42,7 for a column.
See the exampleFirst and last line of the file.
See the example^A / ^E # start / end of the line
Ctrl+Left / Ctrl+Right # word by word
^Y / ^V # page up / page down
M-\ / M-/ # top / bottom of the file
^_ 42 # go to line 42 (also ^/)
M-] # matching bracket
^C # where am I?
Open at the error directly. nano +42 app.js starts on line 42, so you can skip the jump entirely.
# a recorded session, replayed when you press Run ^_ Enter line number, column number: 42 # the cursor lands on line 42 ^C [ line 42/180 (23%), col 1/31 (3%), char 1022/5410 (18%) ] M-/ # now on the last line of the file
Worth remembering
| Keys | Moves to |
|---|---|
^A / ^E | Start / end of line |
Ctrl+Left / Right | Previous / next word |
^Y / ^V | Previous / next page |
M-\ / M-/ | First / last line |
^_ or ^/ | A line and column you type |
M-] | The bracket that matches |
Cut, copy, paste
nano cuts whole lines by default, which suits config files. Mark a region when you need less than a line.
Each ^K cuts the line the cursor is on. Press it several times in a row and the lines stack into one clipboard, so ^K ^K ^K then ^U moves a three line block.
Cut the current line, or the marked text.
See the exampleCopy the line or marked text without removing it.
See the examplePaste what you cut or copied.
See the exampleStart a mark, then move to select.
See the example^K # cut this line
^K ^K ^K # cut three lines into one clipboard
^U # paste at the cursor
M-6 # copy this line, keep it in place
M-A then arrows # mark a region; ^K or M-6 acts on it
M-T # cut from here to the end of the file
Moving the cursor starts a fresh clipboard. Cuts only stack while you press ^K back to back. Move away and the next cut replaces the clipboard.
# a recorded session, replayed when you press Run # cursor on the line: PORT=3000 ^K ^K # PORT and HOST are cut together M-\ # jump to the top of the file ^U # both lines are pasted above the first line
Worth remembering
| Keys | Does |
|---|---|
^K | Cut line or selection |
M-6 | Copy line or selection |
^U | Paste |
M-A or ^6 | Start or end a mark |
Shift+arrows | Select as you move |
M-T | Cut to the end of the file |
Search and replace
Find a setting, jump between matches, and change every occurrence in one pass, with or without regular expressions.
While a search or replace prompt is open, toggles appear on the help lines: M-C for case sensitive, M-R for regular expressions and M-B to search backwards.
Find the next match.
See the exampleNext or previous match of the last search.
See the exampleReplace, asking at each match.
See the exampleIn replace: change all the rest at once.
See the example^W timeout # find
M-W # next match
M-Q # previous match
^\ # replace: pattern, then replacement
Y / N / A # this one, skip, all the rest
M-R (at a prompt) # regular expression mode
M-C (at a prompt) # match case
Press Y a few times before A. Checking the first matches by hand catches a pattern that is wider than you meant, like 3000 inside 30001.
# a recorded session, replayed when you press Run ^W Search: PORT # jumps to the first match M-W [ This is the only occurrence ] ^\ Search (to replace): 3000 Replace with: 8080 A [ Replaced 2 occurrences ]
Worth remembering
| At a prompt | Toggles |
|---|---|
M-C | Case sensitive |
M-R | Regular expression |
M-B | Search backwards |
Up / Down | Earlier searches from history |
^C | Cancel |
Undo and select
Take back a mistake, bring it back again, and select text the way you would in any other editor.
Undo in nano is M-U, not Ctrl+Z, which suspends programs in a terminal. If you press Ctrl+Z by habit, type fg at the shell to get nano back.
M-U # undo
M-E # redo
Shift+arrows # select while moving
M-A # start a mark, M-A again ends it
M-D # count words, lines and characters
Ctrl+Z is not undo here. It pauses nano and drops you at the shell. Your work is safe: fg brings it straight back.
# a recorded session, replayed when you press Run # delete a line by mistake ^K M-U # the line is back ^Z [1]+ Stopped nano config.yml fg # nano returns with your edits intact M-D Words: 214 Lines: 31 Chars: 1388
Worth remembering
| Keys | Does |
|---|---|
M-U | Undo |
M-E | Redo |
Shift+arrows | Select text |
M-A or ^6 | Toggle a mark |
M-D | Word, line and character count |
Indent and comment
Shift blocks left and right, comment them out, and keep indentation steady while you type.
Indent and comment work on the current line, or on every line of a marked region. M-3 picks the comment style from the file's syntax, so it writes # in YAML and // in JavaScript.
Indent the line or selection.
See the exampleUnindent it.
See the exampleComment or uncomment.
See the exampleTurn auto indent on or off.
See the exampleM-A then Down x3 # mark three lines
M-} # indent them one step
M-{ # take it back
M-3 # comment them out
M-I # auto indent on or off
^J # justify (rewrap) a paragraph
Turn auto indent off before pasting. Pasted code arrives already indented, so auto indent adds a step to every line and makes a staircase. M-I, paste, M-I.
# a recorded session, replayed when you press Run # three lines of nginx.conf marked with M-A M-} # each line moves one tab to the right M-3 # each line now starts with # M-3 # and the comments come off again
Worth remembering
| Keys | Does |
|---|---|
M-} / Tab on a mark | Indent |
M-{ / Shift+Tab on a mark | Unindent |
M-3 | Comment or uncomment |
M-I | Toggle auto indent |
^J | Justify the paragraph |
Display toggles
Flip the view to suit the file: line numbers for code, soft wrap for prose, visible whitespace for YAML and Makefiles.
Toggles last for the session only. When you find a view you always want, make it permanent in .nanorc, which module 11 covers.
Line numbers in the margin.
See the exampleShow tabs and trailing spaces.
See the exampleSoft wrap long lines on screen.
See the exampleHide the help lines for more room.
See the exampleM-N # line numbers
M-P # show whitespace
M-S # soft wrap long lines
M-X # hide or show the help lines
M-C # keep the cursor position visible
M-Y # syntax colour on or off
M-O # type spaces when you press Tab
M-P settles tab arguments. A Makefile needs real tabs and YAML refuses them. Show whitespace and you can see which one you typed.
# a recorded session, replayed when you press Run nano Makefile M-N # numbers appear in the left margin M-P # tabs show as » and trailing spaces as · M-X # the two help lines disappear
Worth remembering
| Keys | Toggles | nanorc name |
|---|---|---|
M-N | Line numbers | set linenumbers |
M-P | Whitespace display | set whitespace |
M-S | Soft wrapping | set softwrap |
M-C | Cursor position | set constantshow |
M-O | Tabs to spaces | set tabstospaces |
M-X | Help lines | set nohelp |
Several files
Open more than one file at once, switch between them, pull one file into another, or save under a new name.
Every file you open sits in its own buffer. The title bar shows which one you are in, and ^X closes only the current buffer, so you leave nano once the last one closes.
Opens both, each in a buffer.
See the exampleNext and previous buffer.
See the exampleInsert another file at the cursor.
See the exampleSave a copy under another name.
See the examplenano server.js config.js # two buffers
M-> # next buffer (also M-.)
M-< # previous buffer (also M-,)
^R header.txt # insert a file here
^R then ^T # browse for the file
^O server.backup.js # save as a new name
^R then M-F opens a new buffer. Inside the Read File prompt, M-F switches between inserting into this file and opening it on its own.
# a recorded session, replayed when you press Run nano server.js config.js M-> # the title bar now reads config.js ^R File to insert [from ./]: header.txt [ Read 6 lines ] ^X # config.js closes and server.js is back
Worth remembering
| Keys | Does |
|---|---|
M-> or M-. | Next buffer |
M-< or M-, | Previous buffer |
^R | Insert a file |
^R then M-F | Open it as a new buffer |
^T in a file prompt | Browse the folders |
Run commands
nano can run a shell command and drop its output into the file, or pipe your text through a tool and replace it with the result.
Press ^T to open the Execute prompt. A plain command inserts its output at the cursor. Start the command with | and the marked text, or the whole buffer, goes through it instead.
Insert a command's output.
See the exampleSort the marked lines in place.
See the exampleSpell check, if spell or hunspell is installed.
See the exampleRun the linter set for this syntax.
See the example^T date # insert today's date
^T ls *.conf # insert a file list
M-A ... ^T |sort # sort the marked lines
^T |jq . # pretty print JSON in place
^T ^S # spell check
^T ^Y # linter
Mark first, then pipe. Without a mark, |sort sorts the whole file. M-U undoes it if that was not the plan.
# a recorded session, replayed when you press Run ^T Command to execute: date Sat Oct 3 10:22:41 IST 2026 # the date is now in the file at the cursor # mark four unsorted host names, then ^T Command to execute: |sort # the four lines are replaced in sorted order
Worth remembering
| At the Execute prompt | Does |
|---|---|
cmd | Insert the output of cmd |
|cmd | Pipe the mark or buffer through cmd |
^S | Spell check |
^Y | Run the linter |
^O | Run the formatter |
^C | Cancel |
Startup flags
Choose how nano behaves for one file, right on the command line: numbers, indents, tab width, mouse, backups.
Flags apply only to that launch. They are perfect for a one off, such as opening a Python file with four space indents on a server where you do not own the .nanorc.
Line numbers.
See the exampleAuto indent, spaces for tabs, tab width 4.
See the exampleClick to place the cursor, scroll with the wheel.
See the exampleKeep file~ as a backup on save.
See the examplenano --version
nano -l app.js # line numbers
nano -i -E -T 4 tool.py # four space indents
nano -m README.md # mouse support
nano -B nginx.conf # keep a backup
nano -v /var/log/syslog # view only
nano +42,7 app.js # line 42, column 7
-v is the safe way to read config. View mode cannot change the file, so you can open anything under /etc without the risk of a stray keypress.
# a recorded session, replayed when you press Run nano --version | head -1 GNU nano, version 7.2 nano -l -i -E -T 4 tool.py # numbers on, Tab types four spaces, new lines keep their indent nano -B nginx.conf ^S ls nginx.conf* nginx.conf nginx.conf~
Worth remembering
| Flag | Long form | Does |
|---|---|---|
-l | --linenumbers | Line numbers |
-i | --autoindent | Keep indent on new lines |
-E | --tabstospaces | Spaces for Tab |
-T 4 | --tabsize=4 | Tab width |
-m | --mouse | Mouse support |
-B | --backup | Backup on save |
-v | --view | Read only |
Your .nanorc
Write your preferences once in ~/.nanorc and every nano you open starts the way you like it.
Each line is set plus an option, the same names as the toggles and flags. Ubuntu already loads syntax colours from /usr/share/nano; the include line makes sure of it on other systems.
mkdir -p ~/.cache/nano/backups
nano ~/.nanorc
nano app.py # opens with your settings
nano -I app.py # ignore .nanorc this once
Keep it in your dotfiles repo. Copy one file to a new server and nano behaves the same everywhere.
# a recorded session, replayed when you press Run mkdir -p ~/.cache/nano/backups nano ~/.nanorc # paste the starter config, then ^S and ^X nano app.py # line numbers, a scroll indicator and four space tabs, every time
A starter ~/.nanorc
# ~/.nanorc
set linenumbers
set autoindent
set tabsize 4
set tabstospaces
set indicator
set mouse
set constantshow
set backup
set backupdir "~/.cache/nano/backups"
include "/usr/share/nano/*.nanorc"
Back up into one folder. backupdir keeps the ~ files out of your projects, and the folder must exist first.
Worth remembering
| Option | Does |
|---|---|
set linenumbers | Number every line |
set autoindent | New lines keep the indent |
set tabsize 4 | Tab width |
set tabstospaces | Spaces instead of tabs |
set indicator | A scroll bar on the right |
set mouse | Mouse support |
set backup | Write file~ on save |
Everyday gotchas
Editing files you do not own, making nano the default for git and cron, and getting work back after a crash.
Use sudoedit for system files. It copies the file, opens the copy in nano as you, with your own .nanorc, and writes it back as root only when you save.
sudoedit /etc/hosts # edit a root file safely
echo 'export EDITOR=nano' >> ~/.bashrc
git config --global core.editor nano
select-editor # Ubuntu: crontab's editor
ls *.save # emergency saves
nano saves your work when it is killed. If the terminal dies, nano writes file.save next to the file. Open it, check it, then rename it over the original.
# a recorded session, replayed when you press Run nano /etc/hosts # edit, then ^S [ Error writing /etc/hosts: Permission denied ] # quit with ^X and N, then open it the right way sudoedit /etc/hosts git config --global core.editor nano && git config --get core.editor nano ls *.save notes.txt.save
Worth remembering
| Problem | Fix |
|---|---|
Alt keys do nothing on macOS | Press Esc, then the key |
Permission denied on save | Reopen with sudoedit |
Pasted code becomes a staircase | M-I off before pasting |
Long lines run off screen | M-S soft wrap |
Pressed Ctrl+Z | Type fg at the shell |
Terminal crashed | Look for file.save |
Which one do I need?
Find the job, press the keys. Every shortcut here is covered in a module above, and ^G inside nano shows the full list.
| I want to | Run |
|---|---|
| Save | ^S (or ^O to choose the name) |
| Quit | ^X |
| See every shortcut | ^G |
| Go to line 42 | ^_ 42 |
| Top / bottom of file | M-\ / M-/ |
| Start / end of line | ^A / ^E |
| Cut a line | ^K |
| Copy a line | M-6 |
| Paste | ^U |
| Select text | M-A or Shift+arrows |
| Find | ^W, then M-W for next |
| Find and replace | ^\ |
| Undo / redo | M-U / M-E |
| Indent / unindent | M-} / M-{ |
| Comment out | M-3 |
| Line numbers | M-N |
| Show whitespace | M-P |
| Soft wrap | M-S |
| Next file | M-> |
| Insert a file | ^R |
| Insert a command's output | ^T |
| Word count | M-D |
| Edit a root file | sudoedit /path |
| Make it permanent | ~/.nanorc |