The downside was the cost of starting an executable from scratch, which isn't that bad on Linux, plus the cost of whatever interpreter was handling the request if you didn't write it in C. Such as PHP or Perl ('use CGI' was very popular).
(what better solution would you choose in 2024 for a web server where you have 1,000 customers each of which has one or two CGI scripts that get on average one request every few minutes?)
Probably because there was not yet any data AT ALL about demand from the network, the patterns that random visitors could cause, etc.
“I don’t get why the Romans didn’t build suspension bridges with concrete, steel, and cables.”
Granted there will be some CPU intensive services that will benefit from C but I still wouldn’t call CGI “pretty fast”.
That’s not to say I’d dislike CGI. I made a fair amount of money in my early career based on services written to use CGI. But the reasons why we had things like fastcgi, mod_perl, and the HTTP servers included in language frameworks was to mitigate the overhead of expensive process forking.
When you wrote a web application before the ~2010s you wouldn't start of with a library with webserver building blocks to which to attach routing + behaviour. It sounded crazy at that time, especially when you where building websites with a scripting language like PHP/Perl/Python/Ruby. It sorta became the norm with the rise in popularity of event driven IO, through projects like NodeJS and the rising popularity of Go.
Even today, at least in the PHP world, we still mostly use the CGI based approach to running code (though it's through a more modern interface such as "fast cgi"), with an inbetween service that handles process (fpm - fastcgi process manager). I'm sure other dynamic languages have something similar, though there is a large wave of people pushing for more application server style deployments in those ecosystems as well (which is more feasible today).
1. proxy support was limited or non-existent in the main webservers that existed at the time, so routing the request over would have been a problem.
2. there were no frameworks to speak of to make any of this easier. CGI.pm would help parse and decode GET and POST data. That was just about all there was. There was no PHP (as it exists now,) no Rails, no http frameworks like actix-web. Nothing.
“Inefficient and prone to break” is an excellent description of CGI. Most practical people moved away from as quickly as possible.
It does leave some performance on the table, which was addressed by things like mod_perl or FastCGI (incl. PHP-FPM). There's also the middle ground solution of mod_cgid, which has a specialized daemon fork the CGI process instead (presumably the specialized daemon has a much smaller memory image than the full server).