Back

/ 4 min read

Git-Style Diff for Strings, Objects, and Arrays

In today’s fast-paced development world, having a tool that can clearly and concisely show you exactly what changed — whether in simple strings, nested objects, or complex arrays — is a game-changer.

That’s exactly why diff-leven was born. Inspired by the simplicity of Levenshtein’s algorithm and craving clarity in complex data diffs.

What is diff-leven?

diff-leven is a lightweight npm package for comparing:

  • Strings
  • Objects
  • Arrays
  • Primitive values (numbers, booleans, etc.)

🎮 Playground: link

📖 Background: Why Levenshtein Distance?

The Levenshtein distance measures the minimum number of single-character edits — insertions, deletions, or substitutions — required to transform one string into another. It’s been foundational in spell checkers since its introduction by Levenshtein. By extending this algorithm to objects and arrays, diff-leven lets you compare complex data structures with the same precision and clarity you’d expect from a Git diff.

🔍 What Makes diff-leven Stand Out?

1. Multi-Type Support

  • Objects & Nested Structures: Detect changes deep in your data tree.
  • Arrays: Smart content-based matching highlights moves, additions, and deletions in lists.
  • Strings: Character-level diff with optional similarity percentages.
  • Primitives: Even numbers and booleans are first-class citizens.

2. Git-Style, Colorized Output

By default, diff-leven presents differences with clear ”+” (additions) and ”–” (deletions) markers, complete with ANSI colors for terminal readability.

3. Flexible Configuration

Options like ‘keysOnly’, ‘ignoreKeys’, ‘ignoreValues’, and ‘outputKeys’ let you tailor the diff to your needs—focus on structure, skip timestamps, or force inclusion of critical fields.

🚀 Getting Started

Install

Terminal window
npm install diff-leven

How to Use

const { diff, diffRaw, isDiff } = require('diff-leven');
// Basic diff (string output)
console.log(diff({ foo: 'bar' }, { foo: 'baz' }));
// Output:
// {
// - foo: "bar"
// + foo: "baz"
// }
// Raw diff object
const rawDiff = diffRaw({ foo: 'bar' }, { foo: 'baz' });
console.log(JSON.stringify(rawDiff, null, 2));
// Output:
// {
// "type": "changed",
// "path": [],
// "oldValue": { "foo": "bar" },
// "newValue": { "foo": "baz" },
// "children": [
// {
// "type": "changed",
// "path": ["foo"],
// "oldValue": "bar",
// "newValue": "baz"
// }
// ]
// }
// Boolean diff check
console.log(isDiff({ foo: 'bar' }, { foo: 'baz' }));
// Output: true
console.log(isDiff({ foo: 'bar' }, { foo: 'bar' }));
// Output: false
// With options
console.log(
isDiff(
{ foo: 'bar', timestamp: 123 },
{ foo: 'bar', timestamp: 456 },
{ ignoreKeys: ['timestamp'] },
),
);
// Output: false (identical when ignoring timestamp)
// No colors
console.log(diff({ foo: 'bar' }, { foo: 'baz' }, { color: false }));
// Output:
// {
// - foo: "bar"
// + foo: "baz"
// }
// Full output
console.log(diff({ foo: 'bar', b: 3 }, { foo: 'baz', b: 3 }, { full: true }));
// Output:
// {
// - foo: "bar"
// + foo: "baz"
// b: 3
// }
// Ignore keys
console.log(
diff({ foo: 'bar', b: 3 }, { foo: 'baz', b: 3 }, { ignoreKeys: ['b'] }),
);
// Output:
// {
// - foo: "bar"
// + foo: "baz"
// }
// Ignore values
console.log(
diff({ foo: 'bar', b: 3 }, { foo: 'baz', b: 3 }, { ignoreValues: true }),
);
// Output showing structural differences only
// Show similarity info for string changes
console.log(
diff('hello world', 'hello there', { color: true, withSimilarity: true }),
);
// Output:
// - 'hello world'
// + 'hello there' (73% similar)
// Output specific keys
console.log(
diff({ foo: 'bar', b: 3 }, { foo: 'baz', b: 3 }, { outputKeys: ['foo'] }),
);
// Output:
// {
// - foo: "bar"
// + foo: "baz"
// }
// Combine options
console.log(
diff(
{ foo: 'bar', b: 3 },
{ foo: 'baz', b: 3 },
{
keysOnly: true,
ignoreKeys: ['b'],
ignoreValues: true,
outputKeys: ['foo'],
full: true,
color: false,
},
),
);

Explore Examples: Check out the basic example script to see more patterns in action.


⚙️ Options Matrix

OptionTypeDefaultDescription
colorbooleantrueUse colorized output
keysOnlybooleanfalseOnly compare object keys
fullbooleanfalseOutput the entire object tree
outputKeysstring[][]Always include these keys in output
ignoreKeysstring[][]Ignore these keys when comparing
ignoreValuesbooleanfalseIgnore value differences, focus on structure
withSimilaritybooleanfalseShow similarity info for string changes

💡 Real-World Use Case: API Regression Detector

Imagine you’re maintaining a client library. You fetch an API response:

const oldResponse = await fetch(...).then(res => res.json());
const newResponse = ...;
console.log(diff(oldResponse, newResponse));

Instantly see if a ratio changed, a property is missing, or an endpoint returned unexpected structure.

✨ Conclusion

Whether you’re debugging a tricky migration, reviewing API changes, or just curious about how two versions of your data differ, diff-leven delivers clear, colorized diffs in seconds. By marrying the classic Levenshtein algorithm with a flexible JavaScript API, it empowers developers to visualize changes across any serializable structure.

Ready to give it a spin? Install it today and let the diffing begin! 🛠️🎉

References

  1. NPM package — diff-leven
  2. GitHub README — diff-leven
  3. Levenshtein distance overview — Wikipedia
  4. Medium article on diff-leven