aiodns

Async DNS resolver for Python asyncio — thin wrapper around pycares (c-ares C library) providing non-blocking DNS resolution. aiodns features: DNSResolver class, query() for A/AAAA/MX/NS/CNAME/TXT/SRV/PTR/NAPTR/SOA records, gethostbyname() for simple hostname resolution, resolve() for A/AAAA with fallback, cancel() for in-flight query cancellation, loop integration with asyncio, and DNS query type constants. Essential for async web crawlers, agentic HTTP clients, and services making high volumes of DNS lookups without blocking the event loop.

Evaluated Mar 06, 2026 (0d ago) v3.x
Homepage ↗ Repo ↗ Developer Tools python aiodns dns async asyncio resolver pycares c-ares
⚙ Agent Friendliness
59
/ 100
Can an agent use this?
🔒 Security
79
/ 100
Is it safe for agents?
⚡ Reliability
74
/ 100
Does it work consistently?

Score Breakdown

⚙ Agent Friendliness

MCP Quality
--
Documentation
75
Error Messages
72
Auth Simplicity
95
Rate Limits
90

🔒 Security

TLS Enforcement
72
Auth Strength
80
Scope Granularity
75
Dep. Hygiene
80
Secret Handling
88

DNS queries are unencrypted UDP by default — susceptible to DNS spoofing and monitoring. For security-sensitive applications use DNS-over-HTTPS (DoH) or DNS-over-TLS (DoT) providers. aiodns does not support DoH/DoT natively. DNS reconnaissance (bulk domain enumeration) raises legal/ethical concerns — only query domains you have authorization to enumerate.

⚡ Reliability

Uptime/SLA
72
Version Stability
75
Breaking Changes
75
Error Recovery
72
AF Security Reliability

Best When

Async Python services (aiohttp, FastAPI, Starlette) needing high-volume non-blocking DNS resolution — aiodns's c-ares backend provides true async DNS without blocking the event loop unlike socket.getaddrinfo().

Avoid When

Your code is synchronous (use dnspython/socket), you need DNS zone management, or you need response caching (add aiocache layer).

Use Cases

  • Agent async hostname resolution — import aiodns; resolver = aiodns.DNSResolver(); async def resolve_host(hostname): result = await resolver.gethostbyname(hostname, socket.AF_INET); return result.addresses[0] — non-blocking DNS in asyncio agent; HTTP client building blocks for crawlers; resolves thousands of hostnames concurrently without blocking event loop
  • Agent MX record lookup — resolver = aiodns.DNSResolver(); result = await resolver.query('gmail.com', 'MX'); mx_records = sorted(result, key=lambda r: r.priority); primary_mx = mx_records[0].host — async MX record query; agent email validation checks deliverability without blocking; query() returns record-type-specific objects
  • Agent bulk DNS resolution — resolver = aiodns.DNSResolver(nameservers=['8.8.8.8', '1.1.1.1']); tasks = [resolver.gethostbyname(h, socket.AF_INET) for h in hostnames]; results = await asyncio.gather(*tasks, return_exceptions=True) — parallel DNS resolution; agent domain scanning resolves 1000 hostnames concurrently; return_exceptions=True prevents one failure from canceling all
  • Agent reverse DNS lookup — resolver = aiodns.DNSResolver(); result = await resolver.query('1.1.1.1.in-addr.arpa', 'PTR'); hostname = result[0].name — PTR record query for IP-to-hostname; agent IP enrichment adds hostname context to IP addresses; in-addr.arpa format required for IPv4 PTR queries
  • Agent custom nameserver resolution — resolver = aiodns.DNSResolver(nameservers=['192.168.1.1'], timeout=5.0); try: result = await resolver.query('internal.corp', 'A'); except aiodns.error.DNSError as e: handle_nxdomain(e) — configure internal DNS; agent service discovery queries private DNS for internal service endpoints; timeout prevents stalls on unreachable nameservers

Not For

  • Sync Python code — aiodns requires asyncio event loop; for sync DNS use dnspython or socket.getaddrinfo()
  • Full DNS toolkit — aiodns is resolution only; for DNS zone management, record parsing, or authoritative DNS use dnspython
  • Production DNS caching — aiodns does not cache responses; implement TTL-aware caching layer (aiocache + aiodns) for high-volume production use

Interface

REST API
No
GraphQL
No
gRPC
No
MCP Server
No
SDK
Yes
Webhooks
No

Authentication

Methods: none
OAuth: No Scopes: No

No auth — DNS queries use standard UDP/TCP port 53. Custom nameservers specified in DNSResolver constructor.

Pricing

Model: open_source
Free tier: Yes
Requires CC: No

aiodns is MIT licensed. Free for all use.

Agent Metadata

Pagination
none
Idempotent
Full
Retry Guidance
Not documented

Known Gotchas

  • pycares must be installed separately — pip install aiodns requires pycares C extension; on systems without C compiler or c-ares dev headers, installation fails; agent Docker images must: apt-get install -y libcares-dev; or use pre-built wheels; ImportError at aiodns import if pycares not installed
  • DNSResolver must be created inside event loop — aiodns.DNSResolver() created at module level before asyncio.run() raises RuntimeError in newer Python; agent code must create resolver inside async context: async def main(): resolver = aiodns.DNSResolver(); or as class attribute initialized in async __init__; module-level resolver creation is not safe
  • query() result type depends on record type — resolver.query('domain', 'A') returns list of AResult objects with .host; resolver.query('domain', 'MX') returns list of MXResult with .priority and .host; resolver.query('domain', 'TXT') returns list of TXTResult with .text as bytes list; agent code must handle different result schemas per query type
  • No built-in retry on SERVFAIL — aiodns raises DNSError on SERVFAIL without automatic retry; recursive resolvers sometimes return SERVFAIL transiently; agent DNS code should implement: async def resolve_with_retry(host, retries=3): for _ in range(retries): try: return await resolver.query(host, 'A'); except aiodns.error.DNSError: await asyncio.sleep(0.1); raise
  • gethostbyname() vs query() return different formats — resolver.gethostbyname(host, AF_INET) returns HostResult with .addresses list; resolver.query(host, 'A') returns list of AResult with .host string; agent code mixing both APIs will encounter AttributeError accessing wrong attribute; use consistent API across codebase
  • Concurrent queries share resolver state — single DNSResolver instance handles all concurrent queries via c-ares event loop; closing resolver with resolver.cancel() cancels ALL in-flight queries not just one; agent code canceling one slow query must use separate resolver instance per query group or implement per-query timeout with asyncio.wait_for()

Alternatives

Full Evaluation Report

Detailed scoring breakdown, competitive positioning, security analysis, and improvement recommendations for aiodns.

$99

Scores are editorial opinions as of 2026-03-06.

5208
Packages Evaluated
26151
Need Evaluation
173
Need Re-evaluation
Community Powered