Skip to content

uk-sponsors

Search the UK visa sponsor register from the command line

Role
Creator & Sole Developer (Open Source)
Dates
Nov 2026
Status
In development
  • TypeScript
  • Node.js
  • Commander
  • Vitest
  • csv-parse
  • cli-table3
  • Node.js zlib
  • ESLint
  • Prettier
  • pnpm
  • GitHub Actions
  • GOV.UK Content API
  • Companies House data
View on GitHub
uk-sponsors

Summary

A working, tested CLI that turns the Home Office sponsor register into one command. On the 2 November 2026 register it indexed 127,486 sponsors and matched 104,118 of them to Companies House industry codes. 137 tests pass in CI on Linux, macOS and Windows.

The problem

If you need a UK work visa, only a company on the Home Office "Register of licensed sponsors: workers" can hire you. GOV.UK publishes it as a CSV file with over 140,000 rows, and it changes almost every day. The file is slow to open in Excel and impossible to use on a phone. It doesn't say what each company does. There is no simple way to ask "which software companies in Leeds can sponsor a Skilled Worker visa?"

My role

Solo project. I own the whole project. I wrote the requirements, chose the stack, built every command and wrote the tests, docs and CI.

What I built

  • Wrote the PRD, build plan and seven decision notes.
  • Built the update pipeline: Content API lookup, host check, streaming download, column check and atomic index swap.
  • Built name matching that ignores case, accents and punctuation, and treats Ltd/Limited and &/and as the same.
  • Built the search, check and stats commands with table, JSON and CSV output.
  • Built optional industry search: a 472 MB Companies House zip is unzipped with Node's zlib as it downloads, then matched to sponsors by name and town.
  • Set up CI on Linux, macOS and Windows, and a tag-triggered npm publish workflow with provenance.

Architecture

A Node.js CLI written in TypeScript and built with tsc, with no bundler. It has three runtime libraries: commander, csv-parse and cli-table3. - src/register: find the CSV through the GOV.UK Content API, download it (streaming, host allow-list, length check), parse it, check the columns, normalise names, build the index and run queries. - src/companies-house: find the newest snapshot, unzip it as it streams with node:zlib, parse it and match companies to sponsors. - src/commands: one file per command (update, enrich, search, check, stats). - src/output: table, JSON and CSV writers, with colour that turns off for pipes and NO_COLOR. The index files live in the user's cache folder. Only update and enrich use the network; search works offline.

Key decisions and trade-offs

Chose: find the CSV through the GOV.UK Content API, and only accept links on assets.publishing.service.gov.uk, even after redirects. Because: the JSON is a published interface and the page layout is not. A changed or tampered response can't point the tool at another server. Chose: check the required columns by name on every load, and stop with a message that names what is missing. Because: a renamed column must never give wrong answers quietly. The same check covers the Companies House columns. Chose: exit codes 0 for success, 1 for something the user can fix, and 2 for a network problem or a change on GOV.UK or Companies House. Because: a script can tell "you did something wrong" apart from "the source changed". Every error also says what to do next. Chose: one JSON index file, built in a temp folder, read back, then swapped in with a single rename. Because: the metadata and the data can never get out of step, and a failed update leaves the old data working.

Hardest problem and how I solved it

The data is big and can change at any time, and the tool must never give wrong answers quietly. update streams the 10.4 MB register and checks the API shape and the required columns. It rejects a register with fewer than 1,000 rows and a download shorter than its Content-Length, and only swaps in the new index after reading it back. Any change on GOV.UK's side is reported by name, with exit code 2. Industry data was harder. Companies House publishes one 472 MB zip holding 5,711,779 companies. Rather than add a zip library or save the file, enrich skips the zip header and inflates the rest with Node's built-in zlib as it downloads. The output goes straight into the CSV parser and the matcher, and nothing large touches the disk. A sponsor is matched by name and town, by name alone when only one company has that name, or by a former name in the same town. Anything less certain is left out. On the 2 November 2026 register that matched 104,118 of 127,486 sponsors (81.7%).

Testing and quality

137 tests in 10 files, run with Vitest. They use small fake files only: the register CSV has a UTF-8 BOM, Windows line endings, accented names, quoted commas and Temporary Worker routes, and a fake Companies House CSV is zipped inside the test. Nothing downloads the real data: update and enrich are tested against a local fake server. The tests cover column-change errors, the host allow-list, a bad download leaving no half-written file, the streaming unzip with data arriving in small chunks, all three match types, CSV formula escaping and NO_COLOR. CI runs typecheck, lint, tests and build on Ubuntu (Node 22 and 24), macOS and Windows (Node 24).

Results

  • 127,486 sponsors indexed from the 2 November 2026 register
  • 81.7% of sponsors matched to Companies House industry codes
  • 137 tests in CI on Linux, macOS and Windows

Versions 1 and 1.1 are built, and all checks pass on four CI targets. It is open source under the MIT licence and runs from source with Node.js 22.12 or newer. The npm publish workflow is ready, but no version has been released yet.

Key features

  • update: downloads the latest register from GOV.UK, with progress.
  • search: filters by --name, --city, --county, --route, --rating and --limit.
  • Industry search with --industry presets (software, IT services, fintech, health tech, legal services) or --sic codes, after the optional enrich step.
  • check "<name>": yes or no for one company, with its Companies House number, status and SIC codes, or up to 5 close matches.
  • stats: register date, totals, top 10 towns and cities, and counts by route, licence type and rating.
  • Table, --json and --csv output, and --out to save to a file.
  • Reminder on every command when the data is more than 7 days old.
  • Works offline after update, with no telemetry. Runs on macOS, Linux and Windows.

Out of scope

Version 1 leaves out matching against job adverts, SOC code or salary data, a web interface, and alerts when companies join or leave the register. Industry matches depend on names and on the SIC codes companies give Companies House, so about 18% of sponsors (mostly NHS trusts, universities, charities and sole traders) have no industry data.