vdomains
A CLI that extends Vercel's domain management with interactive TUI search, health diagnostics, DNS reconciliation, transfer workflows, and JSON mode for scripting and agentic pipelines. Built with Ink for rich terminal UI.
Why This Exists
Vercel is building self-driving infrastructure — deployments, edge functions, observability, all converging toward a platform that manages itself. Their AI layer is getting smarter about how projects are built and shipped. But domains are still a manual step. You leave your editor, navigate the dashboard, search for availability, configure DNS, and hope you don't misconfigure a CNAME along the way.
vdomains closes that gap. It puts the full domain lifecycle in the terminal — search, buy, configure, diagnose, renew — so getting the domain you've been wanting for your project is one command, not a context switch. Every command supports --json, which means AI agents like Claude Code can manage domains programmatically as part of a larger workflow. The domain step stops being a manual interruption and becomes part of the pipeline.
Every command supports --json — AI agents like Claude Code can manage domains programmatically as part of a larger workflow.
The domain step stops being a manual interruption and becomes part of the pipeline.
See It Work
A CLI for the full Vercel Domains lifecycle — search, buy, manage, diagnose, transfer, and renew domains.
Discovery & Search
The search command is an interactive TUI built with Ink — it queries availability across TLDs with pricing, renders results in a navigable list with vim keybindings (j/k to move, enter to select, c to copy), and lets you open in browser or buy directly. Run it without a query inside a project directory and it infers a search term from the nearest package.json, stripping the @scope/ prefix.
The suggest command generates name variations from keywords in batches of 6, checking 50+ variations with incremental progress display. The dual-mode architecture — interactive Ink components for humans, structured JSON for machines — runs through every command. Same business logic, different rendering layer.
# Install globally
npm install -g vdomains
# Authenticate via OS keychain
vdomains login
# Search availability across TLDs (interactive)
vdomains search mycoolapp
# Infer search term from nearest package.json
vdomains search
# Full health check — DNS, SSL, HTTP, headers
vdomains health mycoolapp.dev
# Detect DNS drift against a config file
vdomains reconcile domains.json
# List all domains with expiry info
vdomains expiring 30
# Transfer a domain into Vercel
vdomains transfer-in mycoolapp.dev
# Everything supports structured output
vdomains list --json | jq '.[] | .name'# Install globally
npm install -g vdomains
# Authenticate via OS keychain
vdomains login
# Search availability across TLDs (interactive)
vdomains search mycoolapp
# Infer search term from nearest package.json
vdomains search
# Full health check — DNS, SSL, HTTP, headers
vdomains health mycoolapp.dev
# Detect DNS drift against a config file
vdomains reconcile domains.json
# List all domains with expiry info
vdomains expiring 30
# Transfer a domain into Vercel
vdomains transfer-in mycoolapp.dev
# Everything supports structured output
vdomains list --json | jq '.[] | .name'Diagnostics
The health command replaces the dig-curl-openssl dance with a single invocation. It runs 7 checks in parallel: DNS resolution, nameserver verification (with Vercel detection), CNAME validation, SSL certificate inspection via raw TLS socket (not fetch — you need getPeerCertificate() for expiry and issuer data), HTTPS connectivity, HTTP-to-HTTPS redirect, and security headers. Each check is independently timed, and the overall status uses a fail > warn > pass > skip hierarchy.
The reconcile command was the more interesting problem. It loads expected domain state from a JSON config file and compares against live DNS, reporting ok, drift (with field-level diffs showing expected vs. actual), or extra (domains in Vercel but not in config). DNS comparison is order-agnostic and case-insensitive using Sets, with special handling for MX records (priority-exchange tuples) and TXT records (joined from split DNS buffers). It catches the manual changes that silently drift from your intended configuration.
{
"domains": [
{
"domain": "myapp.com",
"vercel": true,
"dns": {
"CNAME": ["cname.vercel-dns.com"]
}
},
{
"domain": "myapp.dev",
"vercel": true
}
]
}{
"domains": [
{
"domain": "myapp.com",
"vercel": true,
"dns": {
"CNAME": ["cname.vercel-dns.com"]
}
},
{
"domain": "myapp.dev",
"vercel": true
}
]
}Auth & Lifecycle
Token resolution follows a three-tier hierarchy: --token flag, VERCEL_TOKEN environment variable, then OS keychain via keytar. This matters because interactive use should be seamless (keychain), CI/CD needs environment variables, and one-off commands need a flag override. The same pattern shows up in every CLI I build — it's the difference between a tool that works in your terminal and one that works everywhere.
Transfer workflows handle both directions with WHOIS contact management. Renewal tracking surfaces expiring domains with color-coded urgency (red for expired, yellow for <30 days). The goal was covering the full domain lifecycle so you never need to context-switch to a dashboard for routine operations.
Token resolution: --token flag > VERCEL_TOKEN env var > OS keychain
The same pattern shows up in every CLI I build — it's the difference between a tool that works in your terminal and one that works everywhere.