domain-check-lib
Rust library for checking domain availability using RDAP and WHOIS protocols. The same engine that powers the domain-check CLI.

Why use the library?
- Domain registrar dashboards — check availability in real time as users type
- SaaS platforms — let customers claim a custom domain during onboarding
- Brand monitoring — scan TLDs for trademark squatting on a schedule
- CI/CD pipelines — validate domain ownership before deploy
- Bulk research tools — check thousands of domains with streaming results
At a Glance
- 1,200+ TLDs via IANA bootstrap, 32 hardcoded as offline fallback
- Dual protocol — RDAP-first with automatic WHOIS fallback via IANA server discovery
- Up to 100 concurrent checks with configurable concurrency
- Streaming support — process results as they arrive via
futures_util::Stream
- Rich metadata — registrar, creation/expiration dates, status codes, nameservers
- 11 built-in TLD presets — startup, tech, creative, finance, etc.
- Domain expansion — expand base names across TLD lists automatically
- Comprehensive error types — timeout, network, parse, bootstrap errors with recovery hints
- Pure async Rust — built on tokio + reqwest, no OpenSSL dependency
Want a ready-to-use CLI instead? See domain-check.
Quick Start
[dependencies]
domain-check-lib = "1.0.1"
tokio = { version = "1", features = ["rt-multi-thread", "macros"] }
use domain_check_lib::DomainChecker;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let checker = DomainChecker::new();
let result = checker.check_domain("example.com").await?;
match result.available {
Some(true) => println!("{} is AVAILABLE", result.domain),
Some(false) => println!("{} is TAKEN", result.domain),
None => println!("{} status is UNKNOWN", result.domain),
}
Ok(())
}
Usage Examples
Bulk Domain Checking
use domain_check_lib::{DomainChecker, CheckConfig};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let config = CheckConfig::default()
.with_concurrency(20)
.with_detailed_info(true);
let checker = DomainChecker::with_config(config);
let domains = vec![
"example.com".to_string(),
"google.org".to_string(),
"github.io".to_string(),
];
let results = checker.check_domains(&domains).await?;
for result in results {
match result.available {
Some(true) => println!("{} is available", result.domain),
Some(false) => println!("{} is taken", result.domain),
None => println!("{} status unknown", result.domain),
}
}
Ok(())
}
Streaming Results
use domain_check_lib::DomainChecker;
use futures_util::StreamExt;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let checker = DomainChecker::new();
let domains = vec![
"example.com".to_string(),
"startup.org".to_string(),
"mybrand.net".to_string(),
];
let mut stream = checker.check_domains_stream(&domains);
while let Some(result) = stream.next().await {
match result {
Ok(r) => println!("{}: {:?}", r.domain, r.available),
Err(e) => eprintln!("Error: {}", e),
}
}
Ok(())
}
Custom Configuration
use domain_check_lib::{DomainChecker, CheckConfig};
use std::time::Duration;
let config = CheckConfig::default()
.with_concurrency(50) .with_timeout(Duration::from_secs(10)) .with_whois_fallback(true) .with_bootstrap(true) .with_detailed_info(true);
let checker = DomainChecker::with_config(config);
TLD Management & Domain Expansion
use domain_check_lib::{
DomainChecker, get_all_known_tlds, get_preset_tlds,
initialize_bootstrap, expand_domain_inputs,
};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let checker = DomainChecker::new();
initialize_bootstrap().await?;
let all_tlds = get_all_known_tlds();
println!("Loaded {} TLDs", all_tlds.len());
let startup_tlds = get_preset_tlds("startup");
let domains = expand_domain_inputs(
&["myapp".to_string(), "mystartup".to_string()],
&startup_tlds,
);
let results = checker.check_domains(&domains).await?;
let available: Vec<_> = results.iter()
.filter(|r| r.available == Some(true))
.collect();
println!("Found {} available domains", available.len());
Ok(())
}
Bootstrap & WHOIS Discovery
use domain_check_lib::{initialize_bootstrap, get_whois_server};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
initialize_bootstrap().await?;
if let Some(server) = get_whois_server("com").await {
println!(".com WHOIS server: {}", server); }
Ok(())
}
Error Handling
use domain_check_lib::DomainCheckError;
match checker.check_domain("invalid-domain").await {
Ok(result) => println!("Success: {:?}", result),
Err(DomainCheckError::InvalidDomain { domain, reason }) => {
eprintln!("Invalid domain '{}': {}", domain, reason);
}
Err(DomainCheckError::NetworkError { message, .. }) => {
eprintln!("Network error: {}", message);
}
Err(DomainCheckError::Timeout { operation, duration }) => {
eprintln!("Timeout after {:?}: {}", duration, operation);
}
Err(e) => eprintln!("Other error: {}", e),
}
Data Structures
DomainResult
pub struct DomainResult {
pub domain: String, pub available: Option<bool>, pub info: Option<DomainInfo>, pub check_duration: Option<Duration>, pub method_used: CheckMethod, pub error_message: Option<String>, }
DomainInfo
pub struct DomainInfo {
pub registrar: Option<String>,
pub creation_date: Option<String>,
pub expiration_date: Option<String>,
pub status: Vec<String>,
pub updated_date: Option<String>,
pub nameservers: Vec<String>,
}
Protocol Support
| Protocol |
Role |
Details |
| RDAP |
Primary |
Structured JSON responses, 1,180+ TLDs via IANA bootstrap, rich data |
| WHOIS |
Fallback |
Targeted queries via IANA server discovery, smart parsing, rate limiting |
| Bootstrap |
Discovery |
Bulk IANA registry fetch (enabled by default), 24h cache, zero maintenance |
Related
License
Licensed under either of Apache License, Version 2.0 or MIT License at your option.
Contributing
Contributions welcome. See CONTRIBUTING.md for setup and workflow.