# Typhoeus: Parallel HTTP Requests for Ruby via libcurl and Hydra

> Typhoeus is a Ruby gem that wraps libcurl to make fast, reliable HTTP requests, including concurrent requests through a class called Hydra. It provides a clean interface for serial and parallel HTTP operations with callback-based response handling, file uploads, and response streaming.

**typhoeus/typhoeus** —  Typhoeus wraps libcurl in order to make fast and reliable requests.

- Repository: https://github.com/typhoeus/typhoeus
- Website: http://rubydoc.info/github/typhoeus/typhoeus
- Stars: 4,134 · Forks: 440
- Language: Ruby
- License: MIT
- Published: 2026-09-23 · Updated: 2026-09-23 · Language: en
- Canonical page: https://hysenlabs.com/projects/typhoeus-typhoeus

## What Typhoeus Solves in a Ruby HTTP Stack

Most Ruby HTTP clients make one request at a time: build a request, send it, wait for the response, then send the next one. For code that calls multiple external APIs or fetches many URLs in sequence, this serialization adds latency proportional to the number of requests.

Typhoeus addresses this by wrapping libcurl, the widely deployed C library for URL transfers, and adding a parallel request manager called Hydra. With Hydra, a developer can queue ten requests and fire them all at once, collecting responses when the entire batch completes. The total wall time approaches the slowest individual response rather than the sum of all response times.

The gem provides three core classes. Request encapsulates a single HTTP request and its options. Response holds the result, accessible through code, total_time, headers, and body. Hydra manages the connection pool and orchestrates parallel execution.

Typhoeus also exposes convenience class methods (Typhoeus.get, Typhoeus.post, and so on) for one-off serial requests when parallelism is not needed. Both paths, serial and parallel, return Response objects through the same interface.

## The Three-Class Design: Request, Response, and Hydra

A Request object is built with a URL and an options hash. The first argument is the URL. The second is optional settings:

```ruby
request = Typhoeus::Request.new(
  "www.example.com",
  method: :post,
  body: "this is a request body",
  params: { field1: "a field" },
  headers: { Accept: "text/html" }
)
```

The method option defaults to :get. The params key builds URL query parameters. The body key sends the request body. For POST requests, the Content-Type is set automatically to application/x-www-form-urlencoded when body is a hash. For PUT, PATCH, and other methods, the content-type must be set explicitly if URL-encoded parameters are needed:

```ruby
Typhoeus.put("www.example.com/posts/1",
        headers: {'Content-Type'=> "application/x-www-form-urlencoded"},
        body: {title:"test post updated title", content: "this is my updated content"}
    )
```

The Response object exposes response.code for the HTTP status code, response.total_time for the elapsed time, response.headers for the response headers, and response.body for the response body as a string. It also provides convenience methods: response.success? returns true for 2xx codes, and response.timed_out? returns true when the request hit a timeout.

## Installing Typhoeus and Making Serial Requests

Install Typhoeus using Bundler:

```
bundle add typhoeus
```

Or install it directly:

```
gem install typhoeus
```

For serial (blocking) requests, the class-level convenience methods cover the standard HTTP verbs:

```ruby
Typhoeus.get("www.example.com")
Typhoeus.head("www.example.com")
Typhoeus.put("www.example.com/posts/1", body: "whoo, a body")
Typhoeus.patch("www.example.com/posts/1", body: "a new body")
Typhoeus.post("www.example.com/posts", body: { title: "test post", content: "this is my test"})
Typhoeus.delete("www.example.com/posts/1")
Typhoeus.options("www.example.com")
```

Each call returns a Response object immediately after the request completes. To follow HTTP redirects, pass followlocation: true in the options hash:

```ruby
Typhoeus.get("www.example.com", followlocation: true)
```

Proxy support is available through the proxy option, with optional proxyuserpwd for authenticated proxies. The proxyuserpwd value is a colon-separated username and password, matching the format of the userpwd option for basic authentication.

## Hydra: Issuing Many Requests in Parallel

Hydra is the parallel request manager. Create an instance, queue requests, and call run to block until all complete:

```ruby
hydra = Typhoeus::Hydra.new
10.times.map{ hydra.queue(Typhoeus::Request.new("www.example.com", followlocation: true)) }
hydra.run
```

The run call is blocking. It returns once every queued request has finished. Each request's Response object is populated after run returns, accessible through request.response.

Hydra also supports chaining requests inside on_complete callbacks. When the first request finishes, its callback can build and queue a third request based on the first response, and Hydra will execute it as part of the same run:

```ruby
hydra = Typhoeus::Hydra.hydra

first_request = Typhoeus::Request.new("http://example.com/posts/1")
first_request.on_complete do |response|
  third_url = response.body
  third_request = Typhoeus::Request.new(third_url)
  hydra.queue third_request
end
second_request = Typhoeus::Request.new("http://example.com/posts/2")

hydra.queue first_request
hydra.queue second_request
hydra.run
```

In this pattern, first_request and second_request run in parallel. When first_request completes, its callback queues third_request, which then runs before hydra.run returns. The call is still blocking for the caller.

## Callbacks, Streaming Large Responses, and File Uploads

Typhoeus uses callbacks for response handling. The on_complete callback fires after each request finishes and receives the Response object:

```ruby
request = Typhoeus::Request.new("www.example.com", followlocation: true)

request.on_complete do |response|
  if response.success?
    # hell yeah
  elsif response.timed_out?
    log("got a time out")
  elsif response.code == 0
    log(response.return_message)
  else
    log("HTTP request failed: " + response.code.to_s)
  end
end

request.run
```

For large responses, the on_body callback streams chunks to a handler instead of buffering the full response. When on_body is set, Typhoeus does not store the complete response in memory:

```ruby
downloaded_file = File.open 'huge.iso', 'wb'
request = Typhoeus::Request.new("www.example.com/huge.iso")
request.on_headers do |response|
  if response.code != 200
    raise "Request failed"
  end
end
request.on_body do |chunk|
  downloaded_file.write(chunk)
end
request.on_complete do |response|
  downloaded_file.close
end
request.run
```

To interrupt a stream before it finishes, return :abort from the on_body block. This stops the stream cleanly and avoids memory leaks that would occur from using return or raise to exit the block.

File uploads use a File object as a body parameter in a POST request. Typhoeus sets the filename and Content-Type from the file and the Mime::Types library.

## When Typhoeus Is the Wrong Choice

Typhoeus depends on libcurl being installed in the deployment environment. In containerized or minimal environments, this dependency must be explicitly included. The gem will not load if libcurl is missing, and the error is a native extension failure rather than a clear Bundler message.

For applications that need retry logic, circuit breaking, or multiple HTTP backend options, Typhoeus does not ship those out of the box. The callback model handles errors but provides no built-in retry policy. Teams that want those behaviors without writing them manually will need additional code or a different library.

Typhoeus is also not the right choice for applications that interact primarily with REST APIs and want automatic JSON serialization and deserialization. The library operates at the raw HTTP level. The body is a string or a hash; JSON parsing is the caller's responsibility.

The last push to the repository was on 2026-03-10. The gem has an active CI configuration in .github/workflows/ci.yml and a separate experimental workflow. The CHANGELOG.md tracks version history. The MIT license permits unrestricted commercial use. Teams adopting Typhoeus should monitor the repository for updates since the gap between the last push and today is over six months.

## How Typhoeus Compares to Faraday

Faraday is a Ruby HTTP client library that uses an adapter model. Rather than binding to a specific underlying HTTP implementation, Faraday accepts different adapters (net/http, HTTPClient, Excon, and others including Typhoeus itself). Middleware can be stacked for logging, retry, caching, and authentication.

The key difference is the abstraction level. Faraday abstracts away the underlying connection library and provides a middleware stack for cross-cutting concerns. Typhoeus is the underlying connection library: it manages libcurl connections and provides the parallel Hydra API. When parallelism is needed and libcurl is acceptable as a dependency, Typhoeus is the lower-level choice with direct control over request batching.

Faraday can use Typhoeus as an adapter for its parallel request feature, which means the two are not strictly alternatives. For a greenfield Ruby project that needs flexible HTTP with middleware support and no libcurl requirement, Faraday is the more general starting point. For a project that specifically needs high-throughput parallel requests with the Hydra API and is comfortable depending on libcurl, Typhoeus is appropriate directly.

## Conclusion

Typhoeus is the right tool for Ruby applications that need to issue many HTTP requests concurrently and want a libcurl-backed implementation with explicit parallel control through the Hydra class. The on_body streaming callback makes it well suited for downloading large files without buffering the entire response in memory. The last push to the repository was on 2026-03-10. Teams adding Typhoeus to a new project should verify that its libcurl dependency is available in their deployment environment and review the CHANGELOG.md for any recent API changes. Applications that need a flexible adapter model, multiple backend options, or built-in retry middleware will find Faraday a better starting point.

## FAQ

### How does Typhoeus make parallel HTTP requests?

Typhoeus uses the Hydra class to manage parallel requests. Create a Hydra instance, queue multiple Request objects with hydra.queue, then call hydra.run, which blocks until all requests complete. Each request's response is available through request.response after run returns.

### How do I install Typhoeus in a Ruby project?

Run bundle add typhoeus to add Typhoeus to your Gemfile and install it, or gem install typhoeus to install it directly. Typhoeus requires libcurl to be installed in the environment; the gem wraps libcurl through a native extension.

### How does Typhoeus handle HTTP errors and timeouts?

Use the on_complete callback on a request object. The response argument provides success? for 2xx codes, timed_out? for timeout detection, code for the HTTP status code, and return_message for curl-level errors (when code equals 0, no HTTP response was received at all).

## Sources

- [Issues](https://github.com/typhoeus/typhoeus/issues)
- [License: MIT](https://github.com/typhoeus/typhoeus/blob/master/LICENSE)
- [Project website](http://rubydoc.info/github/typhoeus/typhoeus)
- [README](https://github.com/typhoeus/typhoeus/blob/master/README.md)
- [typhoeus/typhoeus on GitHub](https://github.com/typhoeus/typhoeus)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/typhoeus-typhoeus
