← Back to blog
dns-checker

How to Check DNS Propagation

Learn to check DNS propagation with dig, nslookup, and Node.js. Understand TTL, caching, and why DNS changes take time to go live worldwide.

dnsnetworkingdevopsmonitoringdeveloper-tools

Check DNS Propagation



You just updated your DNS records. The registrar says the change is saved. But when you visit the domain, it still points to the old server. You clear your browser cache, flush your local DNS, try a different network — still the old IP. This is DNS propagation, and it is not broken. It is working exactly as designed. DNS changes take time to ripple through the global network of recursive resolvers because those resolvers cache records according to TTL values. This guide explains why propagation takes the time it does, how to check progress from the command line, and how to programmatically verify that your changes have reached every region.

Why DNS Propagation Takes Time



DNS is not a single database. It is a distributed, hierarchical caching system. When you change a DNS record, here is what actually happens:

  • You update the record at your DNS provider (Cloudflare, Route 53, etc.).
  • Your provider's authoritative nameserver now serves the new record.
  • Recursive resolvers worldwide (Google 8.8.8.8, Cloudflare 1.1.1.1, ISP resolvers) still have the old record cached.
  • Each resolver keeps serving the cached record until its TTL (Time To Live) expires.
  • After TTL expiry, the resolver queries the authoritative nameserver and gets the new record.
  • The resolver caches the new record with the new TTL.


  • The total propagation time depends on the previous TTL value — not the new one. If the old record had a TTL of 86400 (24 hours), some resolvers will serve the old value for up to 24 hours after you make the change.

    Pre-change TTL strategy



    If you know a DNS change is coming, lower the TTL 24-48 hours in advance:

    ; Before (high TTL for performance)
    luxkern.com.  86400  IN  A  203.0.113.50

    ; Step 1: Lower TTL 48 hours before the migration luxkern.com. 300 IN A 203.0.113.50

    ; Step 2: After 48 hours, make the actual change luxkern.com. 300 IN A 198.51.100.75

    ; Step 3: After confirming propagation, raise TTL again luxkern.com. 86400 IN A 198.51.100.75


    With a 300-second (5-minute) TTL, propagation completes in minutes instead of hours.

    Checking DNS Propagation with dig



    dig is the standard DNS lookup tool on Linux and macOS. It shows the exact response from any nameserver you specify.

    Query a specific resolver



    # Google's resolver
    dig @8.8.8.8 luxkern.com A +short


    Output: 203.0.113.50

    # Cloudflare's resolver
    dig @1.1.1.1 luxkern.com A +short


    Output: 198.51.100.75

    Different output means propagation is still in progress. Google's resolver has the old record cached; Cloudflare's has already fetched the new one.

    Check TTL remaining



    dig @8.8.8.8 luxkern.com A +noall +answer


    Output:

    luxkern.com.    247    IN    A    203.0.113.50


    The 247 is the remaining TTL in seconds. This resolver will keep serving 203.0.113.50 for another 4 minutes before querying the authoritative nameserver again.

    Query the authoritative nameserver directly



    # Find the authoritative nameservers
    dig luxkern.com NS +short


    Output:

    ns1.cloudflare.com.
    ns2.cloudflare.com.


    # Query the authoritative nameserver
    dig @ns1.cloudflare.com luxkern.com A +short


    Output: 198.51.100.75

    If the authoritative nameserver returns the new IP, the change is saved correctly. All resolvers will eventually converge to this value.

    Check multiple record types



    # A record (IPv4)
    dig luxkern.com A +short

    AAAA record (IPv6)

    dig luxkern.com AAAA +short

    MX record (mail)

    dig luxkern.com MX +short

    TXT record (SPF, DKIM, verification)

    dig luxkern.com TXT +short

    CNAME record

    dig www.luxkern.com CNAME +short


    Trace the full resolution path



    dig luxkern.com A +trace


    This shows every step of the resolution: root servers, TLD servers, authoritative servers. Useful for debugging delegation issues where the wrong nameservers are configured at the registrar.

    Checking DNS Propagation with nslookup



    nslookup ships with Windows and is available on Linux/macOS. Its output is less detailed than dig but sufficient for basic checks.

    # Default resolver
    nslookup luxkern.com

    Specific resolver

    nslookup luxkern.com 8.8.8.8


    Output:

    Server:   8.8.8.8
    Address:  8.8.8.8#53

    Non-authoritative answer: Name: luxkern.com Address: 203.0.113.50


    "Non-authoritative answer" means the response came from a resolver's cache, not directly from the authoritative nameserver.

    # Query a specific record type
    nslookup -type=MX luxkern.com
    nslookup -type=TXT luxkern.com
    nslookup -type=CNAME www.luxkern.com


    Checking DNS Propagation with Node.js



    For automated checks or integration into dashboards, use Node.js's built-in dns module.

    const dns = require("dns");
    const { Resolver } = dns.promises;

    const RESOLVERS = [ { name: "Google", ip: "8.8.8.8" }, { name: "Cloudflare", ip: "1.1.1.1" }, { name: "Quad9", ip: "9.9.9.9" }, { name: "OpenDNS", ip: "208.67.222.222" }, { name: "Level3", ip: "4.2.2.1" }, ];

    async function checkPropagation(domain, expectedIP) { console.log(Checking propagation for ${domain} (expecting ${expectedIP})\n);

    let propagated = 0;

    for (const resolver of RESOLVERS) { const r = new Resolver(); r.setServers([resolver.ip]);

    try { const addresses = await r.resolve4(domain); const match = addresses.includes(expectedIP);

    if (match) propagated++;

    console.log( ${match ? "OK" : "PENDING"} | ${resolver.name.padEnd(12)} (${resolver.ip.padEnd(15)}) -> ${addresses.join(", ")} ); } catch (err) { console.log( ERROR | ${resolver.name.padEnd(12)} (${resolver.ip.padEnd(15)}) -> ${err.code} ); } }

    console.log( \nPropagation: ${propagated}/${RESOLVERS.length} resolvers (${Math.round((propagated / RESOLVERS.length) * 100)}%) ); }

    checkPropagation("luxkern.com", "198.51.100.75");


    Output:

    Checking propagation for luxkern.com (expecting 198.51.100.75)

    OK | Google (8.8.8.8 ) -> 198.51.100.75 OK | Cloudflare (1.1.1.1 ) -> 198.51.100.75 PENDING | Quad9 (9.9.9.9 ) -> 203.0.113.50 OK | OpenDNS (208.67.222.222 ) -> 198.51.100.75 PENDING | Level3 (4.2.2.1 ) -> 203.0.113.50

    Propagation: 3/5 resolvers (60%)


    Run this script on an interval to track propagation over time:

    watch -n 60 node check-propagation.js


    Extended Node.js example: check all record types



    const dns = require("dns");
    const { Resolver } = dns.promises;

    async function checkAllRecords(domain) { const resolver = new Resolver(); resolver.setServers(["8.8.8.8"]);

    const checks = [ { type: "A", fn: () => resolver.resolve4(domain) }, { type: "AAAA", fn: () => resolver.resolve6(domain) }, { type: "MX", fn: () => resolver.resolveMx(domain) }, { type: "TXT", fn: () => resolver.resolveTxt(domain) }, { type: "NS", fn: () => resolver.resolveNs(domain) }, { type: "CNAME", fn: () => resolver.resolveCname(domain) }, ];

    for (const check of checks) { try { const result = await check.fn(); console.log(${check.type.padEnd(6)}: ${JSON.stringify(result)}); } catch (err) { if (err.code === "ENODATA") { console.log(${check.type.padEnd(6)}: (no record)); } else { console.log(${check.type.padEnd(6)}: ERROR - ${err.code}); } } } }

    checkAllRecords("luxkern.com");


    Batch Propagation Check Script



    When migrating multiple subdomains, check them all at once.

    #!/usr/bin/env bash
    set -euo pipefail

    EXPECTED_IP="198.51.100.75" DOMAINS=( "luxkern.com" "www.luxkern.com" "api.luxkern.com" "app.luxkern.com" "docs.luxkern.com" ) RESOLVERS=( "8.8.8.8" "1.1.1.1" "9.9.9.9" "208.67.222.222" )

    for domain in "${DOMAINS[@]}"; do ok=0 total=${#RESOLVERS[@]}

    for resolver in "${RESOLVERS[@]}"; do ip=$(dig @"$resolver" "$domain" A +short 2>/dev/null | head -1) if [ "$ip" = "$EXPECTED_IP" ]; then ((ok++)) fi done

    pct=$((ok * 100 / total)) if [ "$ok" -eq "$total" ]; then status="COMPLETE" elif [ "$ok" -gt 0 ]; then status="PARTIAL " else status="PENDING " fi

    echo "[$status] $domain: $ok/$total resolvers ($pct%)" done


    Output:

    [COMPLETE] luxkern.com: 4/4 resolvers (100%)
    [COMPLETE] www.luxkern.com: 4/4 resolvers (100%)
    [PARTIAL ] api.luxkern.com: 3/4 resolvers (75%)
    [PARTIAL ] app.luxkern.com: 2/4 resolvers (50%)
    [PENDING ] docs.luxkern.com: 0/4 resolvers (0%)


    Understanding TTL in Practice



    TTL values have real trade-offs:

    | TTL | Propagation Time | Cache Benefit | Use Case | |-----|-----------------|---------------|----------| | 60s | ~1 minute | Minimal | Active migration, failover | | 300s | ~5 minutes | Low | Frequently changing records | | 3600s | ~1 hour | Moderate | Standard web records | | 86400s | ~24 hours | High | Stable records, email MX |

    Lower TTLs mean faster propagation but more DNS queries hitting your authoritative servers. For most web applications, 300-3600 seconds is the sweet spot.

    Common TTL mistakes



    Setting TTL to 0: Some resolvers ignore TTL=0 and cache for a minimum of 30-300 seconds anyway. You cannot guarantee instant propagation.

    Forgetting the old TTL: When you change a record, the propagation time is determined by the *previous* TTL, not the new one. If the old TTL was 86400, you wait up to 24 hours even if the new TTL is 60.

    TTL on CNAME records: The effective TTL for a CNAME chain is the minimum TTL of all records in the chain. A CNAME with TTL 3600 pointing to an A record with TTL 60 effectively has a 60-second TTL for the final IP.

    Flushing Your Local DNS Cache



    While waiting for propagation, you can flush your own resolver to see the latest value.

    # macOS
    sudo dscacheutil -flushcache; sudo killall -HUP mDNSResponder

    Windows

    ipconfig /flushdns

    Linux (systemd-resolved)

    sudo systemd-resolve --flush-caches

    Chrome browser

    Navigate to chrome://net-internals/#dns and click "Clear host cache"



    Flushing only affects your machine. Other users and servers worldwide still see their cached values until TTL expires.

    DNS Propagation and CDNs



    CDNs like Cloudflare add a layer of complexity. When you use Cloudflare's proxy (orange cloud icon), the A record points to Cloudflare's IPs, not your origin. Changing your origin server IP requires updating it in Cloudflare's dashboard — DNS propagation is not involved because the public DNS record (Cloudflare's IP) does not change.

    When migrating to or from a CDN, you are changing the actual DNS record, so normal propagation rules apply. Lower your TTL before the migration.

    Using Luxkern DNS Checker



    Checking propagation manually against 4-5 resolvers gives you a rough picture. The Luxkern DNS Checker queries resolvers across 20+ global locations simultaneously and shows you a real-time map of propagation status. No installation, no account required.

    Try DNS Checker free — no credit card required.

    For ongoing monitoring after the migration is complete, PingCheck continuously verifies that your domains resolve correctly and alerts you if DNS records change unexpectedly.

    Try PingCheck free — no credit card required.

    Troubleshooting Slow Propagation



    Record changed at provider but resolvers still show old value



    This is normal. Wait for the old TTL to expire. Check dig +noall +answer to see the remaining TTL on cached records.

    Authoritative nameserver shows old value



    Your change did not save properly at the DNS provider. Log in and verify. Some providers have a "publish" or "deploy" step after editing.

    One specific resolver never updates



    Some ISP resolvers do not respect TTLs and cache aggressively. You cannot fix this — it resolves itself eventually (usually within 48 hours).

    SERVFAIL responses



    The authoritative nameserver is unreachable or misconfigured. Check that your nameserver records at the registrar match your DNS provider's nameservers. Use dig +trace to find where the chain breaks.

    DNS Propagation for Common Scenarios



    Domain migration to a new host



  • Lower TTL to 300 at the old host, 48 hours before migration.
  • Set up the site at the new host and verify it works with a hosts file override.
  • Update the A record to the new IP.
  • Monitor propagation with the batch script above.
  • Keep the old server running for 48 hours to serve stragglers.
  • Raise TTL back to 3600+ after confirming full propagation.


  • Adding a subdomain



    New records propagate instantly for resolvers that have never queried the subdomain. There is no "old" cached record to expire. The only delay is the negative cache TTL from the SOA record (typically 1 hour).

    Email migration (MX records)



    Email is more sensitive to DNS issues than web traffic. Lower the MX record TTL days in advance, and keep the old mail server accepting mail for at least 72 hours after the change.

    For a deeper understanding of each DNS record type and when to use them, read DNS records explained for developers. For monitoring your endpoints after migration, see how to monitor API endpoints.

    Try Luxkern's developer tools free — no credit card required.