As any other Internet protocol, the HTTP protocol has kept evolving over the years and now there are clients and servers distributed over the world and over time that speak different versions with varying levels of success. So in order to get libcurl to work with the URLs you pass in libcurl offers ways for you to specify which HTTP version that request and transfer should use. libcurl is designed in a way so that it tries to use the most common, the most sensible if you want, default values first but sometimes that is not enough and then you may need to instruct libcurl what to do.
Since mid 2016, libcurl defaults to use HTTP/2 for HTTPS servers if you have a libcurl that has HTTP/2 abilities built-in, libcurl will attempt to use HTTP/2 automatically or fall back to 1.1 in case the negotiation failed. Non-HTTP/2 capable libcurls get 1.1 over HTTPS by default. Plain HTTP requests still default to HTTP/1.1.
If the default behavior is not good enough for your transfer, the
CURLOPT_HTTP_VERSIONoption is there for you.
When asking libcurl to use HTTP/2, it is an ask not a requirement. libcurl will then allow the server to select to use HTTP/1.1 or HTTP/2 and that is what decides which protocol that is ultimately used.
When asking libcurl to use HTTP/3 with the
CURL_HTTP_VERSION_3option, that makes libcurl use QUIC to connect to the server and unless the server supports HTTP/3 the transfer will fail - there is no fallback to earlier versions from this in the way the HTTP/2 option works.