Diff Checker — Free Online Tool

Compare two texts and see every added, removed and changed line. Inline, side-by-side and interactive merge views with word-level highlighting.

Use this free online Diff Checker directly in your browser. No signup required, no data leaves your device. Part of Utilier — a collection of 133+ developer utilities.

What is Diff Checker — Compare Two Texts Line by Line?

A diff checker takes two versions of the same text and reports the smallest set of line insertions and deletions that turns the first into the second. This one computes that edit script from a longest-common-subsequence table, then re-diffs each paired changed line at word level, so you see the two characters that moved rather than a whole line painted red. Nothing is uploaded — the comparison runs in the page.

  • Line diff first, word diff second: Both inputs are split on newlines and matched with an LCS pass emitting eq, del and ins operations. Where a run of deletions is followed by a run of insertions, the pairs are re-tokenised with /\s+|\S+/ and diffed again, so only differing words carry a highlight. Whitespace runs are tokens too, which is why a trailing space is visible.
  • Three views of one result: Inline stacks the result in a single column with - and + prefixes, the way git diff prints. Side by side uses a two-column grid with independent line numbers per side. Merge turns each hunk into a decision. The operation list is identical; only the rendering differs.
  • Prefix and suffix trimming: Identical leading and trailing lines are stripped before the table is built, so a one-line edit inside a 5,000-line config only costs an LCS over the changed core.
  • A guardrail, not a frozen tab: The LCS table is O(n×m) in time and memory. Past 4,000,000 cells the tool falls back to a positional line-by-line comparison — still useful, but it no longer detects that a block was inserted rather than rewritten.

Why use Diff Checker?

Reading two files side by side and trusting your eyes fails at exactly the differences that matter: a flipped digit, a swapped flag, a stray trailing space. A diff makes the change set explicit and countable.

  • You see the change, not the line: Word-level highlighting means "listen 80;" against "listen 443 ssl;" marks only 80; and 443 ssl;. On a long line — a CSP header, a connection string, a minified rule — that is the difference between one second and five re-reads.
  • A count you can act on: The status line reports "+N added, -N removed" after every run. Expected a one-line change and got +14 −9? Your editor reformatted the file or rewrote line endings, and you know before you commit.
  • Merge without a merge tool: Merge mode resolves two plain texts hunk by hunk — Use Original, Use Changed, Both or Skip — and builds the result live with its own Copy and Download. Useful when two people edited the same .env and there is no VCS history to lean on.
  • No upload, no account: Both panes stay in the browser tab, which matters when the things you are comparing are production configs, customer exports, or a signed payload you may not paste into a hosted service.

When to use Diff Checker

Reach for it whenever "what actually changed here?" is the question and there is no git history to answer it.

  • Reviewing an edit to nginx, systemd, .env or docker-compose config before applying it to a running host.
  • Comparing two API responses captured at different times, after pretty-printing both so line boundaries are stable.
  • Checking whether a dependency bump touched anything beyond the version string in package.json or a lockfile excerpt.
  • Proof-reading two drafts of documentation and getting a per-word change list instead of tracked-changes soup.
  • Reconciling two exports of the same dataset — CSV rows, translation keys, ID lists — where lines were added, removed or reordered.
  • Confirming a formatter or codegen step is idempotent: run it twice, diff the outputs, expect +0 added, -0 removed.

How to use Diff Checker

The diff recomputes automatically about 200 ms after you stop typing, so most sessions are paste, paste, read.

  1. Load the Original pane: Paste into the left box, or use its upload icon to read a local .txt, .html, .css, .js, .json, .md, .xml, .yaml or .yml file. Line-number gutters appear on both panes.
  2. Load the Changed pane: Paste or upload the second version on the right. Loaded them backwards? Press Swap — it exchanges both panes and re-runs the comparison.
  3. Read the counts first: "+N added, -N removed" appears under the toolbar. Zero on both sides means the texts are identical after the newline split; a number far larger than expected usually means whitespace, not content.
  4. Pick the view that fits: Inline suits small scattered edits and pastes cleanly into a ticket. Side by side suits wide lines and structural moves; ⇄ Flip sides swaps the columns and is enabled only in that mode.
  5. Resolve hunks in Merge mode: Each hunk offers ← Use Original, Use Changed →, Both and Skip; unchanged lines carry through automatically. Undecided hunks contribute nothing, so decide every one before copying or downloading merged.txt.

Key features

  • Word-level highlighting: Paired del/ins lines are re-diffed on whitespace-delimited tokens, so only changed words are marked — in both inline and side-by-side views.
  • Inline, side-by-side and merge modes: One computation, three renderings. Side by side numbers each column independently; ⇄ Flip sides reverses the order when the new version is on your left.
  • Interactive hunk merging: Per-hunk Use Original / Use Changed / Both / Skip buttons assemble a merged result live, with Copy and Download as merged.txt.
  • File upload into either pane: Accepts .txt, .html, .css, .js, .json, .md, .xml, .yaml and .yml. Non-matching extensions are rejected before the file is read.
  • Debounced live recompute: Editing either pane re-runs the diff ~200 ms after the last keystroke, so you can tweak one side and watch the counts move.
  • Large-input fallback: Prefix and suffix are trimmed first; past 4,000,000 LCS cells a positional comparison keeps the tab responsive instead of hanging.

Common use cases

  • Config review before deploy: Confirm the change set is exactly what the ticket described, with nothing extra from an editor's auto-format.
  • Debugging API drift: Compare a known-good response with today's to isolate the field that changed type, vanished, or gained a null.
  • Dependency audits: Check whether a bump touched only versions or also pulled in new entries, integrity hashes and resolved URLs.
  • Editorial review: Get a word-accurate change list between two drafts that you can paste straight into a review thread.
  • Data reconciliation: Line up two CSV or ID exports to find rows present in one but not the other, and rows that moved.
  • Manual conflict resolution: Combine two divergent copies of an untracked file with Merge mode instead of hand-copying lines.

Examples

Inline view. Word-level highlights are shown here between « » — in the tool they are coloured spans.

One changed directive in an nginx block

Original:
server { listen 80; root /var/www;
} Changed:
server { listen 443 ssl; root /var/www;
}
 server {
- listen «80;»
+ listen «443 ssl;» root /var/www; } +1 added, -1 removed

"listen " is shared, so it stays unhighlighted on both rows — only the changed tail is marked.

A version bump plus a new key

Original:
{ "name": "app", "version": "1.4.0", "private": true
} Changed:
{ "name": "app", "version": "1.5.2", "license": "MIT", "private": true
}
 { "name": "app",
- "version": «"1.4.0",»
+ "version": «"1.5.2",»
+ "license": "MIT", "private": true } +2 added, -1 removed

Two insertions against one deletion is the signal that something was added, not merely edited: the version line pairs, the license line has no partner.

Rows added and removed at opposite ends

Original:
alpha
beta
gamma Changed:
beta
gamma
delta
- alpha beta gamma
+ delta +1 added, -1 removed

LCS keeps beta and gamma equal instead of reporting three changes. A positional comparison would have marked all three lines different.

An invisible trailing space

Original:
const x = 1; Changed:
const x = 1;␠
- const x = 1;
+ const x = 1;« » +1 added, -1 removed

The added space is highlighted rather than hidden, which is how you confirm a "no visible change" diff is whitespace-only.

Technical reference

How the comparison is actually computed:

Line algorithm
Longest common subsequence via a dynamic-programming table (Uint32Array rows), backtracked into eq / del / ins operations
Complexity
O(n×m) time and memory on the trimmed core; Myers' 1986 refinement of the same problem runs in O(N+D²) expected time
Fallback threshold
4,000,000 table cells — above it, a positional O(n) line-by-line comparison is used
Line splitting
Split on \n only. A CRLF file keeps its \r, so CRLF vs LF marks every line changed
Word tokenisation
/\s+|\S+/ — whitespace runs are tokens, which makes trailing-space changes visible
Whitespace handling
Significant; there is no ignore-whitespace or ignore-case switch
Debounce
200 ms after the last keystroke in either pane
Privacy
Entirely client-side — no request carries either input

Common mistakes to avoid

Blaming the tool for a diff where nothing looks different

Why it happens: Every line reported as changed differs by at least one character, but the character may be invisible: a trailing space, a tab against spaces, a non-breaking space pasted from a document, or a \r left over from CRLF. Because the splitter only splits on \n, a Windows-formatted input keeps a carriage return on every line, making every line unequal to its Unix counterpart.

How to avoid it: Read the word-level highlights first — a marked run of pure whitespace names the culprit immediately. Then normalise both sides: run each through the Text Formatter with Trim trailing spaces on, and convert line endings so both inputs use LF before re-comparing.

Diffing minified or single-line content

Why it happens: This is a line-based diff. A minified bundle or a one-line JSON payload is a single line, so any change produces exactly one deletion and one insertion. The word pass then re-tokenises that whole line, which on 200 KB is slow and yields a wall of highlights with no structure to anchor them.

How to avoid it: Give the diff line boundaries first: JSON Formatter for payloads, CSS Beautifier for stylesheets, XML Beautifier for XML. Use the same indent setting on both sides so formatting does not become the diff. For short strings — a token, a hash — use the Advanced String Tools character diff instead.

Assuming the result is the minimal or the "correct" edit script

Why it happens: Several edit scripts usually share the same minimal length, and which one you see depends on tie-breaking. A block moved from the top of a file to the bottom is not shown as a move — LCS has no move operation — so it appears as an unrelated deletion and insertion. Past 4,000,000 cells the positional fallback makes no minimality claim at all.

How to avoid it: Read the diff as one valid description of the change, not as intent. When you suspect a move, search for the deleted text among the insertions; verbatim matches mean nothing was rewritten. For very large inputs, compare the region you care about rather than whole files.

Copying a merged result with hunks still undecided

Why it happens: The merged output includes only hunks you explicitly resolved. Unchanged context passes through automatically, but an undecided hunk contributes nothing — so the result silently omits both versions of that region while still looking complete, because the surrounding lines are present.

How to avoid it: Work top to bottom and confirm every hunk shows as decided before copying. To verify, paste the merged output back into the Original pane and diff it against Changed: remaining gaps appear immediately as deletions.

Treating a textual diff as a review of semantics

Why it happens: A diff reports characters, not meaning. Reordered JSON keys, a differently quoted YAML value, or a reformatted SQL query all appear as changes though the parsed result is identical. The reverse also bites: a one-character edit that flips a boolean or widens a CIDR mask looks like an unremarkable single line.

How to avoid it: Normalise before diffing when structure is the point — format both sides with identical settings, or round-trip both through a canonical form. Then read the remaining diff for meaning, weighting security-relevant values far above the size of the change.

Frequently asked questions

How do I compare two text files online without uploading them?

Paste both versions into the Original and Changed panes, or use each pane's upload icon — the file is read locally with the File API and never leaves the tab. The LCS pass and the word-level highlighting both run in your browser's JavaScript engine, so no request carries your text anywhere. That is what makes the tool usable for production configs, customer data exports, and anything else you are not permitted to paste into a hosted diff service.

What is the difference between inline and side-by-side diff view?

Inline stacks everything in one column with - for removed lines, + for added lines and two spaces for unchanged ones — the same shape as git diff output, which pastes cleanly into a ticket. Side by side renders a two-column grid with Original left, Changed right and independent line numbers per side, which reads better when lines are long or blocks moved. Both views show the same operations and the same word highlights; ⇄ Flip sides reverses the columns and is enabled only while side-by-side is active.

Can a diff checker ignore whitespace or letter case?

Not here. This tool treats whitespace and case as content, which is deliberate for config and code review where an invisible character is often the defect. Whitespace runs are their own tokens, so a trailing space is highlighted rather than hidden. If you need a whitespace-insensitive comparison, normalise both inputs first with the Text Formatter using Trim trailing spaces, Trim leading spaces and Collapse inner spaces, then diff the cleaned copies. For case-insensitive work, convert both sides with the Case Converter's lower case output before pasting.

Why does my diff show every line as changed?

Almost always line endings. Inputs are split on \n only, so a file saved with Windows CRLF keeps a carriage return at the end of every line and none of them can equal an LF counterpart. Indentation changes do the same: converting tabs to spaces, or reindenting from two spaces to four, alters every non-empty line. Check the word-level highlights — if the marked region is pure whitespace you have found it. Normalise line endings and indentation on both sides, then re-run.

How large a file can this diff handle?

Comfortably a few thousand lines, and much more when the versions are mostly the same, because identical leading and trailing lines are trimmed before the expensive pass — a one-line edit in a 5,000-line file only costs an LCS over the changed core. The hard limit is 4,000,000 cells in the comparison table; beyond it the tool switches to a positional line-by-line comparison that stays fast but no longer detects inserted blocks. For very large, genuinely different inputs, compare the relevant section instead.

How does merge mode work in a diff tool?

Merge mode groups the operation list into hunks — runs of removed and added lines separated by unchanged context. Each hunk gets four buttons: ← Use Original keeps the left version, Use Changed → keeps the right, Both keeps left lines followed by right lines, and Skip drops the region. Context lines carry through automatically. The Merged Result box rebuilds after every decision and only resolved hunks contribute, so an undecided hunk leaves a silent gap. When all hunks are decided, copy the result or download merged.txt.

Why does the diff mark a line as removed and added instead of moved?

Because the longest-common-subsequence model has only three operations — keep, delete, insert — and no notion of a move. When a block relocates, the algorithm must describe it as a deletion at the old position and an insertion at the new one, which inflates both counts even though no text was rewritten. To confirm nothing changed, look for the removed lines verbatim among the insertions. Some code review platforms add move detection as a post-processing step; a plain LCS diff does not.

References

Privacy and availability

  • Runs entirely in your browser — zero server processing
  • No signup or account required
  • Works offline once loaded
  • Fast, lightweight, no external dependencies
  • Available as a browser extension for Chrome and Firefox