guzzlehttp/streams
A lightweight PHP library for working with streams, offering object-oriented wrappers, lazy and buffered streams, filtering, limiting, and utility helpers. Once used by Guzzle to power HTTP request and response bodies, it remains useful for composing and manipulating stream data.
StreamInterface implementation? For any team shipping file upload/download, media proxying, CSV/report exports, or log shipping, this is a decision that shows up on the roadmap as "large file handling" and is usually under-scoped.StreamInterface is effectively the industry-standard contract. Committing to it decouples our domain code from a specific HTTP client (Guzzle, Symfony HttpClient, Laravel's Http facade), which preserves the option to swap transports later without a rewrite — a real architectural hedge, not a nice-to-have.Storage/Flysystem surfaces streams, and response()->streamDownload() is the idiomatic egress path. This package sits underneath all three, which means the decision is less "adopt a library" and more "acknowledge the layer you're already depending on transitively."guzzlehttp/psr7, which absorbed this functionality) rather than adding a new direct dependency, and for putting "replace abandoned transitive dependencies" on the platform/tech-debt roadmap.Consider it when:
guzzlehttp/streams is already present transitively and you need to understand, patch, or fork behavior (e.g., CachingStream, PumpStream, NoSeekStream, LazyOpenStream, AppendStream, or the fopen-style StreamWrapper).eof, getContents vs read, __toString idempotency).Look elsewhere when (the default case):
guzzlehttp/psr7, the maintained successor that contains this functionality. Adding an archived package to a greenfield composer.json is an unforced error.Http::withOptions(['stream' => true]), response()->streamDownload(), Storage::readStream(), or Symfony HttpClient's own streaming API. Adding this package directly buys you nothing over what's already installed.psr7, not as an invitation.Decision rule: adopt the interface (Psr\Http\Message\StreamInterface), not this package. If the package is already in the tree, confirm the maintained successor is what's actually resolving.
For executives (one paragraph): This is a low-level, MIT-licensed library that lets our application move large data — uploads, downloads, exports, media, backups — in small chunks instead of loading it all into memory. It is not a feature; it is a cost and reliability control. The relevant business decisions are memory sizing (direct cloud spend), the size ceiling on files customers can move through our product, and whether we can add streaming AI/download experiences without a re-architecture. Two caveats worth thirty seconds of attention: the package is archived, and the correct move is to depend on its maintained successor, guzzlehttp/psr7, which we almost certainly already pull in transitively via Guzzle. So the recommendation is no new vendor, no new spend, no new risk — just a deliberate confirmation that we're on the maintained path and a small tech-debt item if we're not.
For engineering (the substance):
Stream, StreamDecoratorTrait, CachingStream, PumpStream, BufferStream, LazyOpenStream, and StreamWrapper live on in guzzlehttp/psr7. Confirm with composer why guzzlehttp/streams and remove any direct requirement.StreamInterface, not against Guzzle. That keeps us portable across Guzzle, Symfony HttpClient, and future transports, and makes streaming testable with in-memory streams.isSeekable()), __toString() only returning from the current position, unclosed handles leaking file descriptors under Octane, and temp-disk exhaustion from CachingStream/php://temp spill.Http; reach the PSR-7 body via $response->toPsrResponse()->getBody(). Use streamDownload/readStream rather than get() on large payloads. Under Octane, stream lifetimes outlive requests — close explicitly.composer audit, Packagist abandoned flags) so this class of risk surfaces on a schedule rather than during an incident.How can I help you explore Laravel packages today?