Skip to content

linkuity/linkuity

Linkuity

CI License .NET

Open-source entity resolution and golden-record engine.

Linkuity finds the records that refer to the same person or organization, links them into clusters, and merges each cluster into one explainable golden record β€” all inside your own environment.

  • πŸ” Detect duplicates across CSVs, systems, and incremental loads
  • 🧩 Build golden records with source-aware merge rules
  • 🧠 Explain every match with per-field score breakdowns
  • πŸ”’ Run locally or privately β€” no customer data leaves your environment
  • ♻️ Batch or durable incremental resolution as data arrives over time

Linkuity resolving 28 source records into 10 golden records

Quick start

Prerequisites: .NET 10 SDK.

Resolve the bundled 28-record sample into golden records:

git clone https://github.com/linkuity/linkuity.git
cd linkuity
dotnet run --project src/Linkuity.Cli -- run `
  --input samples/people-multi-source/sample.csv `
  --profile samples/people-multi-source/people-multi-source.profile.json `
  --merge-policy samples/people-multi-source/people-multi-source.merge.json `
  --output ./data/output/people-multi-source
Job 5f3a…c21e completed.
Golden records: …/data/output/people-multi-source/golden-records.csv

28 source records from CRM, Marketing, Support, and Billing β†’ 10 golden records. Add --neo4j-export to also write a graph bundle. Next: the guided durable MDM quick start.

The demo above is generated from docs/assets/demo.tape by the Demo GIF workflow β€” see docs/assets.

Before and after

Real systems rarely store a person the same way twice β€” a nickname here, a typo there, a phone number in a different format:

id source first_name last_name email phone address_line
crm-050 CRM Joseph Martinez joseph.martinez@example.com (312) 555-0147 1420 Maple Avenue
mkt-051 Marketing Joe Martinez joe.martinez@example.com 312-555-0147 1420 Maple Ave
sup-052 Support Joesph Martinez joseph.martinez@example.com 312.555.0147 1420 Maple Avenue Apt 3B
bil-053 Billing Joseph Martinez joseph.martimez@example.com 3125550147 1420 Maple Ave Apt 3B

Every mismatch is one you have probably seen in production: a nickname (Joe), a misspelling (Joesph), a one-letter email typo (martimez), one phone in four formats, and an apartment number that only reached two systems.

Linkuity normalizes, blocks, scores, and clusters these into a single golden record:

record_count member_ids first_name email phone address_line
4 crm-050|mkt-051|sup-052|bil-053 Joseph joseph.martinez@example.com +13125550147 1420 Maple Ave Apt 3B

And it is explainable β€” first_name wins by consensus (Joseph over the nickname and the typo), email by CRM source priority (the typo-free address), phone normalizes to one number, and address takes the Billing row with the unit. A golden record is a composite, not a copy of any single row. See how matching works and the people-multi-source sample.

Why Linkuity

Most ways to resolve entities fall into one of three buckets, each with a catch: hosted matching services (you ship customer data to someone else's cloud), closed-source products (you can't inspect or tune how matches are decided), and low-level fuzzy-matching libraries (powerful, but you assemble blocking, scoring, clustering, merging, and persistence yourself).

Linkuity is a complete, open-source engine you run yourself:

Hosted service Closed product Match library Linkuity
Open source βœ• βœ• βœ“ βœ“
Data stays in your environment βœ• varies βœ“ βœ“
Explainable match decisions varies βœ• you build it βœ“
Whole workflow (merge, golden records, persistence) βœ“ βœ“ βœ• βœ“
Durable incremental resolution varies varies βœ• βœ“
Native .NET, cross-platform β€” β€” varies βœ“

Common use cases

  • Customer 360 / MDM β€” one trusted record per customer from many systems
  • CRM cleanup & contact deduplication β€” collapse duplicate people
  • Supplier / vendor consolidation β€” dedupe and standardize organizations
  • Organization resolution β€” match companies across name and domain variants
  • Data migrations β€” dedupe before loading into a new system
  • Incremental identity resolution β€” keep records linked as new data lands
  • Graph analysis β€” export resolved entities to Neo4j and explore the links

How it works

flowchart TD
    A[CSV / sources] --> B[Normalization]
    B --> C[Blocking]
    C --> D[Candidate retrieval]
    D --> E[Scoring]
    E --> F[Decision bands]
    F --> G[Clustering]
    G --> H[Golden records]
    H --> I[Exports & review]
Loading

Comparing every record against every other is NΒ² and doesn't scale, so Linkuity only scores candidate pairs that share a cheap blocking key, combines per-field similarities into one score, and sorts each pair into a decision band: auto-merge, review, or no-match. Accepted pairs cluster transitively, and each cluster merges into a golden record via your source-priority rules β€” with a per-field breakdown you can read back. Full detail (with a worked example): how-matching-works.md.

Batch mode vs durable mode

Batch mode Durable mode
Entry point linkuity run linkuity project / ingest-incremental
State Stateless β€” resolves and forgets Persistent store that remembers
New data Reprocesses the whole file Matched incrementally against stored records
History & review β€” Versioned golden records + review queue
Store backend Output files Local JSON file or PostgreSQL
Reach for it when One-off dedupe, exports, CI Ongoing MDM as data arrives over time

The quick start uses batch mode. For durable mode, follow the durable MDM quick start; to back it with PostgreSQL, see durable-postgres.md.

Key capabilities

  • Matching engine β€” normalization, blocking (including phonetic), weighted similarity scoring, Lucene-backed candidate retrieval
  • Taxonomy-driven β€” ships person and organization built in; a new content type (e.g. the location sample) is a config-only *.profile.json, no code change β€” see docs/configuration.md
  • Explainability β€” persisted per-field score breakdowns and read-back commands
  • Golden records β€” configurable source-priority merge policies; composite output
  • Two modes β€” stateless batch and durable incremental (versioning + review queue)
  • Storage β€” local filesystem + JSON store, or a PostgreSQL durable backend
  • Interfaces β€” CLI, HTTP API, and Docker Compose
  • Graph export β€” Neo4j-ready node/relationship bundle
  • Runtime β€” native .NET 10; cross-platform and single-file deployable
  • License β€” Apache 2.0

Showcases and samples

The samples/ directory has small, self-contained datasets β€” each with a walkthrough and test-pinned expected results β€” covering multi-source people and organization merging, unreliable-field handling, name noise, and durable incremental scenarios. Start with people-multi-source (the 28 β†’ 10 example above).

For a full end-to-end demo on real public data, see showcases/company-resolution β€” resolve real companies across multiple public data sources.

Documentation

Roadmap

Active development. Near-term focus (full plan in docs/roadmap/PLAN.md):

  • Packaged CLI releases so users don't build from source
  • More realistic sample datasets
  • Reproducible quality/cost benchmarks (plan)
  • Better match explanations and review workflows
  • SDK, connector, and plugin guidance
  • Larger-scale private-server deployment examples

Contributing

Contributions are welcome. Start with CONTRIBUTING.md, which covers development setup and the Contributor License Agreement (CLA.md). Please also review CODE_OF_CONDUCT.md, SECURITY.md, and CHANGELOG.md.

License

Linkuity is licensed under the Apache License 2.0.

About

Linkuity is a golden-record engine for data and MDM teams

Resources

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages