TSV to Base64

Turn a block of tab-separated rows into one Base64 string for a JSON field, an HTTP header, or a config file. The grid preview shows how many columns each row really has before you encode, because a tab lost in a copy and paste looks identical to a tab that survived.

Tab-separated rows

source

Base64 string

result

Paste a block of tab-separated rows, drop a .tsv file on the box, or load one of the samples.

0Rows
0Columns
0Source bytes
0Base64 chars
0%Size change
0Ragged rows
Shape check
Data URI

Load a sample

TSV breaks in transit for one reason: the tab is invisible

A tab-separated file has no quoting rules and no escape character. Column boundaries are single U+0009 bytes, and rows end at a newline. That simplicity is the point, and it is also the weakness. Every layer between your file and its destination treats whitespace as something it may reformat.

A web form trims it. A YAML parser rewrites it. A JSON string survives fine until someone pretty-prints the payload. Email clients and chat apps convert runs of tabs into spaces before the message leaves. The receiving side sees a table with the right rows and one column, and nobody notices until a report comes out empty.

Base64 removes the question. The 64 characters in the alphabet are letters, digits, plus, and slash, all of which survive anything that handles text at all. Whatever bytes go in come back out, tabs included, spacing included, trailing spaces on the last cell included.

Check the grid before you encode

Encoding hides mistakes as effectively as it protects data. A row missing a tab and a row with the right structure produce Base64 strings that look equally plausible, and the difference surfaces on the far end. The preview table exists for that reason: it splits your input the same way the decoder will, and marks anything that does not line up.

None of these stop the encoding. They are your data, and you may have reasons for all of them. The check tells you what the decoder will see.

Line endings change the bytes, so they change the string

Base64 encodes bytes, not lines. A file saved on Windows ends rows with 0D 0A. The same file on Linux or macOS ends them with 0A. Both decode to the same table, and the two Base64 strings share almost nothing.

LF endingsa\tb\nc\td
YQliCmMJZA==
CRLF endingsa\tb\r\nc\td
YQliDQpjCWQ=

Set the Line endings control when the string has to match a value produced somewhere else. Checksum comparisons, cache keys, signed request bodies, and test fixtures all fail on a mismatch that reads as identical data. LF is the safer default for anything crossing a network. CRLF belongs in files handed to older Windows tooling that opens them in Notepad.

Mixed endings inside one paste are worth fixing before anything else. The status line flags them, and forcing one style is the fix.

What the options do

Standard against URL safe

The standard alphabet ends with + and /. Both are reserved in a URL, so a Base64 string dropped into a query parameter gets mangled: the plus becomes a space in form decoding, and the slash reads as a path separator in some routers. The URL-safe variant from RFC 4648 section 5 swaps them for - and _, which no URL layer touches.

Use URL safe for query strings, path segments, filenames, and JWT payloads. Use standard everywhere else, since it is what base64_decode in PHP, base64.b64decode in Python, and atob in the browser expect without a translation step.

Padding

Base64 works in groups of three bytes. When the total is not divisible by three, one or two = characters mark the shortfall. Most decoders infer the length and accept a string without them, which is why JWTs drop padding entirely. Some do not, and PHP's decoder in strict mode is one of them. Leave the box ticked unless the format you are targeting asks for unpadded output.

Wrapping

One long line is right for JSON, headers, and query strings. The 76 column option matches MIME from RFC 2045, and 64 columns matches PEM. Pick a wrap only when the receiver expects it, then strip the newlines again before decoding if the decoder is strict about whitespace.

UTF-8 BOM

Excel needs the three byte marker EF BB BF at the start of a file to open it as UTF-8 rather than the system code page. Without it, accented names and CJK text arrive as mojibake. Tick the box when the decoded bytes will be written to a file someone opens in Excel. Leave it off when a parser reads them, because the marker turns up as a stray character on the first header name and quietly breaks a column match.

Size, and the 33 percent tax

Four Base64 characters carry three source bytes, so the encoded form runs roughly 33 percent longer, plus padding and any newlines you add. The meters show the real figures for your input rather than the rule of thumb.

Watch the byte count rather than the character count when your data has accents or CJK text. Load the Accents and CJK sample: ü costs two bytes, costs three, and an emoji costs four. The source looks short and the encoded string does not.

Base64 is not compression and it is not encryption. The string is longer than the source, and anyone with a decoder reads it back in a second. A customer export encoded into a Base64 blob in a log file or a URL is still a plain customer export. Encrypt first when the content is sensitive, then encode the ciphertext.

Where the string goes next

The common destinations, and what each one wants:

Decoding it back

Every language ships a decoder, and the one line version is usually enough:

PHPstrict mode
$tsv = base64_decode($b64, true);if ($tsv === false) { }
Pythonbytes to text
import base64
tsv = base64.b64decode(b64).decode('utf-8')
JavaScriptUTF-8 safe
const bytes = Uint8Array.from(atob(b64), c => c.charCodeAt(0));const tsv = new TextDecoder().decode(bytes);
Shellcoreutils
echo "$B64" | base64 --decode > data.tsv

The JavaScript case deserves a note. Calling atob and using the result as text works only for ASCII, because atob returns a binary string where each character is one byte. Skip the TextDecoder step and a name like Zürich comes back as Zürich. The same asymmetry applies when encoding, which is why this page runs bytes through TextEncoder rather than handing a string to btoa.

After every encode here, the result is decoded again and compared against the source. The status line reports the match, so a silent character mangling shows up before the string leaves the page.

Where this page stops

File input is capped at 2 MB. Everything runs in this tab with no upload, and a browser textarea holding a multi-megabyte table becomes slow to type in long before the encoder struggles. Command line base64 handles a large export in a fraction of the time.

Nothing here converts between formats. The table is encoded exactly as pasted, so a CSV pasted in gets encoded as CSV, commas and all. TSV to CSV handles that conversion, and the shape check only understands tabs.

There is no delimiter guessing. Pipe-separated and semicolon-separated data will encode without complaint and report one column, since a tab is the only separator this page recognises.

Quoted fields containing literal tabs are not supported, because TSV has no quoting rules. The IANA specification tells you to strip tabs from field values rather than escape them. Data holding real tabs inside a cell needs CSV or a different format.

Nothing persists. Close the tab and the input is gone, so save what you need before you leave.

Nearby pages

Going the other direction, Base64 to TSV decodes a string back into a table. For a table you want as structured data instead, TSV to JSON and TSV to XML parse the columns properly. CSV to Base64 covers the comma-separated equivalent, and Base64 validator checks a string someone sent you before you try to decode it.

Questions that come up mid-encode

The things people hit once a real export is in the box.

Why encode TSV at all instead of sending the file?

Because tabs rarely survive text transport. Forms trim whitespace, YAML parsers rewrite it, and chat and email clients convert runs of tabs into spaces. Base64 uses only letters, digits, plus, and slash, so the bytes arrive exactly as they left. When you control both ends and can send a real file upload, send the file.

My Base64 string changed but the table looks the same. Why?

Line endings, almost always. CRLF adds a byte to every row compared with LF, so the two versions share almost no characters. A trailing blank line and a UTF-8 BOM do the same thing. Force LF or CRLF with the control above when the string has to match one produced elsewhere.

Should I pick the URL-safe alphabet?

Only when the string goes into a URL, a path segment, a filename, or a JWT. The standard alphabet ends with plus and slash, which a URL layer rewrites. Everywhere else keep standard, since that is what base64_decode, b64decode, and atob accept without a translation step.

Is it safe to drop the = padding?

Usually. Most decoders work out the length from the string itself, which is why JWTs omit padding. Some are stricter, including PHP base64_decode with the strict flag. Keep padding unless the format you are targeting asks for it to be removed.

What does the ragged rows count mean?

It counts rows whose column count differs from the header row. Importers align columns by position, so a row missing a tab shifts every later value one column left. The preview marks those rows and shows which cells are empty against which are missing entirely.

Why is my encoded string a third longer than the file?

Base64 packs three bytes into four characters, which is a fixed 33 percent increase, plus padding and any line wrapping. It never shrinks anything. If size is the problem, compress the table first and encode the compressed bytes.

Does the BOM option matter?

It matters when the decoded bytes get written to a file that someone opens in Excel, which needs the marker to read the file as UTF-8. Leave it off when a parser consumes the output, because the three extra bytes attach to the first header name and break column matching.

Is my data uploaded anywhere?

No. Encoding, the shape check, and the round-trip verification all run in JavaScript inside this tab. Nothing is sent to a server and nothing is stored. Remember that Base64 is an encoding rather than encryption, so the resulting string still reveals everything to anyone who decodes it.