Both inputs are cut into lines and every distinct line is mapped to an integer, so the inner comparison loop compares numbers instead of strings. The algorithm then fills a table of (n+1) × (m+1) cells to find the longest common subsequence: the longest ordered set of lines that appears in both sides, not necessarily contiguously. Lines on that path are unchanged; every line of the original that is off the path is a deletion, and every line of the changed side that is off the path is an insertion. That is the whole model — there is no notion of "edited line", only a removal next to an addition, which is why a one-character fix prints as− then +.
The cost is O(n × m) in both time and memory, which is why this page trims identical leading and trailing lines before building the table (an optimal LCS always keeps a matching first or last pair, so trimming cannot change the result) and refuses anything past a fixed cell budget rather than allocating it. It is also why real diff tools cap themselves: two 20,000-line files that share nothing would be a 400-million-cell table.
The second consequence is subtler and matters more day to day: the LCS is not unique. When several subsequences tie for longest, the tie is broken by a rule, not by meaning — which is how a diff ends up anchored to a stray closing brace or blank line and produces a hunk that is technically minimal and humanly unreadable. Nothing in the algorithm knows what a function is. Every "smart" behaviour you have seen — move detection, patience or histogram diff, indentation heuristics — is a layer bolted on top precisely because plain LCS output is often the wrong story about what happened.
A moved block reads as two edits
Move a 40-line function from the bottom of a file to the top and the diff shows 40 deletions and 40 additions with no signal that they are the same code. LCS preserves order, so relocated text cannot be matched. This is the single biggest reason reviewing a refactor is painful — the reviewer has to diff the two halves in their head. The practical fix is procedural, not technical: move code in one commit that changes nothing else, then change behaviour in the next, so each diff tells one story.
Line-based is a convention, not a limit
Character-level diffs are more precise, but the entire ecosystem — patch,git apply, code review, merge conflict markers — speaks in whole lines, and a character-level patch cannot be applied by any of it. The usual compromise, used here, is line-based structure with a word-level highlight inside a replaced pair. That refinement is deliberately suppressed when the two lines share less than about 40% of their characters: an intra-line diff of two unrelated lines invents a relationship that does not exist and misleads more than plain −/+ would.
Nothing leaves this machine
The comparison is plain computation, so it runs in the page itself: there is no upload, no API call and no server-side log of what you pasted. That matters because the things people most often want to diff are exactly the things that should not be pasted into a random web form — nginx and Terraform config, Kubernetes manifests, environment files, production log excerpts, customer records. Load the page once and it will keep working with the network off.