Forcing IPv4 or IPv6 in curl keeps a request on one address family when a dual-stack host behaves differently across network paths. That is useful for troubleshooting, reachability checks, and scripts that should fail explicitly instead of quietly using the other family.
The --ipv4 (-4) and --ipv6 (-6) options limit which resolved addresses curl is willing to connect to. Without either option, curl follows its normal dual-stack behavior and can prefer or fall back between IPv6 and IPv4 depending on resolver results and connection timing.
A forced-family request succeeds only when the hostname has an address in that family and the local host has a working route for it. If the chosen family is unavailable, curl fails the transfer instead of switching families, and on some macOS resolver paths an IPv4-only hostname can still appear as an IPv4-mapped IPv6 value such as ::ffff:192.0.0.170.
Steps to force curl to use IPv4 or IPv6:
- Inspect a normal request first to see whether curl is currently considering both address families.
$ curl --silent --show-error --verbose --output /dev/null https://example.com * Host example.com:443 was resolved. * IPv6: 2606:4700:10::6814:179a, 2606:4700:10::ac42:93f3 * IPv4: 104.20.23.154, 172.66.147.243 * Trying 104.20.23.154:443... * Connected to example.com (104.20.23.154) port 443 ##### snipped #####
When both lists are present, curl uses its default dual-stack connection logic. The connected family can change with DNS results, local routing, and timeout behavior.
- Force an IPv4-only connection when the request must ignore AAAA answers.
$ curl --ipv4 --silent --show-error --output /dev/null --write-out 'remote_ip=%{remote_ip}\nresponse_code=%{response_code}\n' https://example.com remote_ip=104.20.23.154 response_code=200The remote_ip value should be a dotted-quad IPv4 address when the request actually stayed on IPv4.
- Force an IPv6-only connection when the request must not fall back to IPv4.
$ curl --ipv6 --silent --show-error --verbose --max-time 5 --output /dev/null https://example.com * Host example.com:443 was resolved. * IPv6: 2606:4700:10::6814:179a, 2606:4700:10::ac42:93f3 * IPv4: (none) * Trying [2606:4700:10::6814:179a]:443... * ipv6 connect timeout after 2495ms, move on! * Trying [2606:4700:10::ac42:93f3]:443... * Connection timed out after 5005 milliseconds * Closing connection curl: (28) Connection timed out after 5005 milliseconds
On a host with working IPv6, the same command connects to one of the IPv6 addresses and completes without ever listing an IPv4 candidate.
- Confirm that --ipv6 blocks fallback by testing an IPv4-only hostname with a short timeout.
$ curl --ipv6 --silent --show-error --verbose --max-time 5 http://ipv4only.arpa/ * Host ipv4only.arpa:80 was resolved. * IPv6: ::ffff:192.0.0.170, ::ffff:192.0.0.171 * IPv4: (none) * Trying [::ffff:192.0.0.170]:80... * ipv6 connect timeout after 2495ms, move on! * Trying [::ffff:192.0.0.171]:80... * Connection timed out after 5006 milliseconds * Closing connection curl: (28) Connection timed out after 5006 milliseconds
The mapped addresses in the verbose output still do not create an IPv4 fallback. Pair forced-family probes with --max-time in automation so an unavailable path fails quickly and clearly.
Mohd Shakir Zakaria is a cloud architect with deep roots in software development and open-source advocacy. Certified in AWS, Red Hat, VMware, ITIL, and Linux, he specializes in designing and managing robust cloud and on-premises infrastructures.
