The Invisible Characters: Understanding Line Endings (CR, LF, and CRLF)
You've connected to your device and you're seeing data, but it's all jumbled on a single line. Or maybe there are strange extra spaces between each line. This frustrating but common issue isn't a problem with the data itself, but with invisible "control characters" called line endings.
~5 minutes

You've connected to your device and you're seeing data, but it's all jumbled on a single line. Or maybe there are strange extra spaces between each line. This frustrating but common issue isn't a problem with the data itself, but with invisible "control characters" called line endings.
The way computers mark the end of a line of text is a quirky relic of the typewriter era, and different operating systems have different standards. Understanding them is key to making your serial terminal output clean and readable.
The Mechanical Origins: CR and LF
On a mechanical typewriter, to start a new line, you had to perform two distinct actions:
- Carriage Return (CR): Push the lever that moves the "carriage" (the part that holds the paper) all the way back to the left, so the next character you type will be at the beginning of the line.
- Line Feed (LF): Turn the roller knob to advance the paper up by one line.
Early computer systems and teletypes mimicked this. They created two separate, non-printable characters in the ASCII table to represent these actions:
CR: Carriage Return (ASCII code 13, or\rin many programming languages)LF: Line Feed (ASCII code 10, or\nin many programming languages)
The Great Divide: How Operating Systems Differ
The problem is that early computer designers didn't agree on a single standard for what should represent a "newline" in a plain text file. This led to three competing standards that persist to this day.
-
Windows (and its predecessor, DOS): Uses the combination of both characters, CRLF (
\r\n). This is the closest to the original typewriter: first, return to the start of the line, then feed to the next line. -
Linux and macOS (and other Unix-like systems): Use only LF (
\n). The logic here is that a single "newline" character should be sufficient to represent the concept of starting a new line. -
Classic Mac OS (pre-OS X): Used only CR (
\r). This standard is now very rare, but you might encounter it with older Apple hardware.
Why This Matters in a Serial Terminal
When your embedded device (like an Arduino) sends text, it has to choose which line ending to send. For example, Serial.println() in Arduino sends CRLF (\r\n) by default.
Here's what happens when there's a mismatch between what your device sends and what your terminal expects or how it interprets these characters:
-
Problem: All text appears on a single, continuously overwriting line.
- Cause: Your device is likely sending only CR (
\r). The terminal cursor returns to the start of the line but never moves down. Each new line of text just prints over the top of the last one.
- Cause: Your device is likely sending only CR (
-
Problem: Text appears on new lines, but the cursor doesn't return to the left, creating a "staircase" effect.
Hello World And so on- Cause: Your device is sending only LF (
\n). The cursor moves down a line but never returns to the beginning.
- Cause: Your device is sending only LF (
-
Problem: There is an extra blank line between every line of text.
- Cause: Your device is sending CRLF (
\r\n), and your terminal is also configured to add an extra line feed every time it sees a carriage return.
- Cause: Your device is sending CRLF (
The Solution: Taking Control
A good serial terminal like serialterminal.app gives you control over how line endings are handled. You can often find settings like:
- "Newline on...": Choose whether a new line is started on CR, LF, or both.
- "Send on Enter": Configure what character(s) are sent when you press the Enter key in the terminal (
CR,LF, orCRLF).
The best practice is to be consistent. If you're writing the code for the device, decide on a standard (LF is a common, modern choice) and stick to it. Then, configure your terminal to match. By understanding these invisible characters, you can finally tame your text display and get the clean, readable output you expect.