Compare two codebases side-by-side. Detect added, deleted, modified, and moved files with a fast, non-blocking diff engine powered by Web Workers.
Differ is a browser-based tool for comparing two project structures — whether local directories or compressed archives (.zip, .war, .jar). It intelligently detects structural and content-level changes, highlights moved files, and presents results in a clean, interactive dashboard with a side-by-side diff viewer.
All heavy computation runs inside a Web Worker, keeping the UI fully responsive even when comparing large projects with thousands of files.
| Feature | Description |
|---|---|
| Folder Picker | Select local directories via the File System Access API |
| Archive Support | Load .zip, .war, and .jar files directly |
| Drag & Drop | Drop archives onto the drop zones |
| Move Detection | Identifies files moved to a different path |
| Content Diff | Whitespace-insensitive side-by-side diff viewer |
| Smart Filtering | Filter results by change type (Added / Modified / Deleted / Moved) |
| File Tree | Collapsible tree with color-coded change indicators |
| Virtualized Lists | Handles thousands of files without performance degradation |
| Non-blocking | All diff processing runs in a Web Worker |
| Dark Theme | Polished dark UI with smooth Framer Motion transitions |
Frontend React 19 + TypeScript + Vite 7
State Zustand
Routing Wouter
Styling Tailwind CSS 4 + Lucide React
Animations Framer Motion
Diff Engine diff-match-patch
Archives JSZip
Virtualization @tanstack/react-virtual
Processing Web Workers (ES modules)
src/
├── core/ # Pure business logic (no DOM dependencies)
│ ├── types.ts # Domain types: FileNode, DiffResult, ChangeType
│ ├── comparator.ts # Main comparison pipeline
│ ├── diffEngine.ts # Whitespace-normalized content diff
│ ├── moveDetector.ts # Move detection by name + hash
│ ├── fileHash.ts # SHA-256 hashing via SubtleCrypto
│ └── filters.ts # Default exclusion patterns
├── store/
│ └── useProjectStore.ts # Zustand global state
├── hooks/
│ ├── useFileLoader.ts # File System Access API
│ ├── useArchiveLoader.ts # JSZip archive extraction
│ └── useDiffWorker.ts # Web Worker wrapper hook
├── workers/
│ └── diff.worker.ts # Off-thread comparison runner
├── components/
│ ├── Layout.tsx
│ ├── Dashboard/ # SummaryCards, ChangeList
│ ├── DiffViewer/ # SideBySideDiff, DiffHeader
│ ├── FileTree/ # FileTreePanel, FileTreeNode
│ └── Loader/ # ProjectLoader drop zones
└── pages/
├── HomePage.tsx
└── ResultsPage.tsx
- Node.js 18 or later
- A modern browser with File System Access API support (Chrome 86+, Edge 86+)
# Clone the repository
git clone https://github.com/yourusername/differ.git
cd differ
# Install dependencies
npm install
# Start the development server
npm run devOpen http://localhost:5173 in your browser.
npm run build
npm run preview- Click Browse Folder to select a local directory, or
- Click Upload Archive to load a
.zip,.war, or.jarfile, or - Drag & drop an archive onto either drop zone
Click Analyze Differences. A progress bar tracks the Web Worker as it processes files in the background.
- Summary cards at the top show counts per change type — click to filter
- Change list (left panel) sorted by impact magnitude — click any row to open its diff
- Side-by-side viewer (right panel) shows line-level changes with color highlighting
- File tree (toggle button, top right) shows the full project tree with color-coded nodes
Click New Comparison to reset and load different projects.
| Type | Color | Description |
|---|---|---|
| Added | Green | File exists only in Project B |
| Deleted | Red | File exists only in Project A |
| Modified | Amber | Same path, different content |
| Moved | Blue | Same name + content, different path |
| Moved + Modified | Violet | Same name, different path and content |
The following paths are automatically ignored during comparison:
node_modules · .git · dist · target · .bin · .venv · .DS_Store · Thumbs.db
| Browser | Support |
|---|---|
| Chrome 86+ | Full |
| Edge 86+ | Full |
| Firefox 111+ | Full (no folder picker) |
| Safari 16.4+ | Partial (no folder picker) |
Note: The folder picker (
showDirectoryPicker) requires a Chromium-based browser. Archive upload works in all modern browsers.
Contributions are welcome! Please follow these steps:
- Fork the repository
- Create a feature branch:
git checkout -b feature/your-feature - Commit your changes:
git commit -m 'feat: add your feature' - Push to the branch:
git push origin feature/your-feature - Open a Pull Request
Distributed under the MIT License. See LICENSE for details.