Library / SDK
composewell/streamly avatar
composewell/streamly

streamly: fused Haskell streams with declarative concurrency

High performance, streaming and concurrent functional programming in Haskell

927 stars71 forksHaskellNOASSERTION

At a glance

What is it?
composewell/streamly is a Haskell library set that fuses stream pipelines through GHC optimizations so that loops compile down to something close to handwritten C, and it adds declarative concurrency on top of those streams. The catch is a large API surface, a custom licence file that GitHub cannot classify, and an explicit upgrade guide between major versions.
Who is it for?
Adopt streamly when your Haskell work is dominated by stream processing over arrays, files or sockets and you want fusion and declarative concurrency in one API instead of stitching together separate streaming, FRP and concurrency packages. Do not adopt it for a small project that only needs a handful of lines of data manipulation, because the module surface and the 0.9 upgrade boundary are real costs.
Can I use it commercially?
Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
Is it still maintained?
Yes. The repository last received commits 3 days ago.
What is it written in?
Mainly Haskell, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on November 7, 2026, and from our analysis. They are not legal advice.

From daily snapshots

Star history

  • composewell/streamly927 ★ · +0
Star history
Repository2026-10-212026-11-07
composewell/streamly927927

0 Stars in the last 17 days, measured from the daily GitHub snapshot. Compare with other projects

Editorial analysis

A whole Haskell ecosystem compressed into one streaming API

Streamly is positioned as a general purpose Haskell library rather than a single focused utility, and the scope is wide enough that it changes how you structure a program. The README describes a unified API covering streaming, concurrency, logic programming, reactive programming, pinned and unpinned arrays, serialization, builders, parsers, unicode processing, file-io, file system events and network-io. All of that lives in the same abstraction, which is the point: the library claims to unify functionality that otherwise comes from disparate Haskell packages.

The stated motivation for that consolidation is partly ergonomic and partly about data representation. The README argues that the complexity of combining lazy, strict, bytestring and text values is removed by using streams for lazy evaluation, and that bytestring and text are generalised to arrays. If your program currently juggles three or four representations of the same payload, that unification is the concrete win.

The audience is Haskell developers who need throughput but do not want to leave the language. The library leans on Haskell's type safety for correctness while claiming performance in the range of C programs, and it advertises fearless declarative concurrency as a first class feature rather than an add-on.

Stream fusion is the mechanism behind the speed claim

The performance story is not micro-optimised loops, it is the removal of intermediate structure. The README states that Streamly fuses stream pipelines using the stream-fusion technique, producing compiled code that is equivalent to handwritten C and eliminating intermediate allocations and function calls. In practice that means a pipeline of transformations becomes one tight loop over the underlying array instead of a chain of intermediate lists that each allocate.

Two implementation details are named, and they are ordinary GHC features rather than anything exotic: `case-of-case` and `spec-constr`. Streamly relies on GHC's stream fusion optimizations, which is why the fusion happens at compile time and why the resulting code can still be modular. The library argues that traditionally you had to choose between modularity and performance, and that with GHC's optimizations you can keep both.

The headline number in the README is a comparative one: Streamly's fused loops can be up to 100 times faster than those of libraries without stream fusion, with a separate streaming-benchmarks repository linked for the comparison against other Haskell streaming libraries. Treat that as the project's own comparison against a category of libraries rather than as a claim about any single product, and check the benchmark repository for the exact conditions before drawing your own conclusions.

Declarative concurrency without locks or thread plumbing

The concurrency model is the part that differs most from typical Haskell practice. Instead of exposing primitives for managing threads and locks, Streamly applies concurrency to the same streaming abstraction you already use. The README describes this as declarative concurrency that abstracts away low-level concurrency management and makes parallelization easier and safer.

Three shapes of concurrent work are named: repeating actions concurrently to produce a stream of results, mapping functions concurrently over a stream, and combining multiple streams concurrently into a single output stream. Note what this implies in practice. A map that should run in parallel across elements is a different combinator from a plain map, and merging sources is expressed as a stream operation rather than as channel plumbing.

The mechanism is still threads underneath, and the topics attached to the project include async and non-determinism. But the interface you write against is deterministic in shape: you describe the shape of the concurrency, and the library decides how to schedule it. For codebases where the current concurrency logic is scattered across manual thread pools, this is the clearest single reason to look at streamly.

Getting it onto a project: packages, docs and the 0.9 upgrade guide

The library is published on Hackage under two package names, `streamly` and `streamly-core`, and the README also points to a project website for the full documentation. There is no single install command in the project documentation, so the practical route is the usual Haskell one: add the package to your cabal.project or stack.yaml and let the build tool resolve it, using the package names above.

What the project does give you in writing is a landing page for newcomers. The Learn By Examples page is described as an introduction to the library, and the streamly-examples repository holds program snippets, plus there is an examples directory in the repository itself. For the specific situation of moving between major versions, the README instructs readers explicitly to read the Streamly 0.9.0 Upgrade Guide at /docs/User/Project/Upgrading-0.8-to-0.9.md. That pointer is worth taking seriously before you plan a port.

The repository layout also tells you how the project is built. There are many cabal.project variants, such as cabal.project.Werror, cabal.project.coverage, cabal.project.doctest and cabal.project.ghc-head, alongside stack.yaml, a flake.nix and a configure.ac script for the autotools route. Continuous integration configuration sits in .circleci and appveyor.yml, and there are dedicated directories for benchmark/, test/, core/ and src/. A project with this many build configurations is a project with a real contributor base and real release discipline, and it is also a project where a newcomer can spend a long time just getting a build to run.

The wider package family and what it adds to the core

Beyond the fundamental constructs, the project ships companion packages that turn streamly into a general purpose toolkit: `streamly-process` for process handling, `streamly-shell` for shell pipelines, and `streamly-coreutils` for coreutils style commands. The README calls these batteries included, and they are the packages that make the library usable for everyday scripting and system programming rather than only for data pipelines.

The topic list attached to the repository shows how wide the surface has become: arrays, async, concurrency, dataflow, filesystem, folds, frp, logic-programming, loops, modular, network, non-determinism, parsers, pipes, reactive-programming, stream-fusion, streaming, unfolds and unicode. Several of those, frp, pipes and logic-programming in particular, correspond to whole Haskell ecosystems that other projects would make you depend on separately. That is the appeal for a team consolidating dependencies. It is also the source of the risk: adopting streamly for its streaming core may pull in surface area you have no intention of using.

The credits section names three projects that influenced the design, vector by Roman Leshchinskiy, foldl by Gabriella Gonzalez and transient by Alberto G. Corona, with a credits directory holding the full list of contributors and their licences.

Where streamly is the wrong tool

Three situations call for a different answer. First, if your work is a short script rather than a sustained pipeline, the library's breadth is a liability. You are signing up for a large API and a fusion model that only pays off when the pipeline is long enough for the intermediate allocations to matter.

Second, if you need to lean on an existing mature ecosystem in a specific area, consolidation can cut both ways. The library states that it delivers equivalent or improved performance for functionality unified from other libraries, but replacing a specialised package that you trust, with a broad one you are adopting from scratch, is a different risk from writing new code in streamly.

Third, and most concretely, there is a compatibility boundary. The 0.8 to 0.9 transition carries its own upgrade guide, which tells you that the API moved in ways large enough to require a document. Code written against older streamly releases is not a drop-in fit for the current line, and there is no GitHub release history to lean on when checking what changed, since the repository publishes no GitHub releases. The version information lives on Hackage and in the CHANGELOG.md file at the repository root.

Maintenance pace, licence wording and the cost of an upgrade

The project is not archived and the last push was on 2026-10-21, so the code is still moving rather than frozen. The upside is that bug fixes and API improvements keep arriving. The downside is that a large and evolving API means the upgrade is part of the cost of ownership, and the 0.9.0 guide shows that these upgrades are not cosmetic.

Licensing is where the packaging metadata and the prose disagree in a way worth flagging. The README states that Streamly is an open source project available under a liberal BSD-3-Clause license. The licence field on the repository, however, records a custom licence type that GitHub cannot classify, and a LICENSE file sits at the repository root, so the authoritative terms are the text in that file rather than the README sentence. The credits directory also records per contributor licences, which matters if you redistribute code.

Professional support is offered by contact address, and a Gitter chat channel is linked for community questions. The upgrade workflow itself runs through cabal.project variants, stack.yaml and flake.nix, so a version bump means picking the right project file and rechecking your build matrix rather than editing a single dependency line.

Editorial conclusion

Adopt streamly when your Haskell work is dominated by stream processing over arrays, files or sockets and you want fusion and declarative concurrency in one API instead of stitching together separate streaming, FRP and concurrency packages. Do not adopt it for a small project that only needs a handful of lines of data manipulation, because the module surface and the 0.9 upgrade boundary are real costs. Verify first that your code can live with the fused model, that you read the Streamly 0.9.0 Upgrade Guide before porting from 0.8, and that the BSD-3-Clause terms in the LICENSE file cover the way you intend to ship your application, since GitHub records the licence as a custom type it cannot classify.

Frequently asked questions

What is streamly used for in Haskell?

It is a library set for streaming, concurrent, reactive and logic programming with a unified API, covering arrays, parsers, file-io, network-io and unicode processing. Its main draw is stream fusion, which compiles pipelines into loops without intermediate allocations.

How do I add streamly to a Haskell project?

The project publishes two Hackage packages, `streamly` and `streamly-core`, so you add the relevant package names to your cabal.project or stack.yaml and let the build tool resolve them. The project documentation does not give a single install command, so the usual Haskell build tool flow applies.

How does streamly handle concurrency compared to plain Haskell threads?

The concurrency model is declarative and expressed through the streaming API itself: repeat actions concurrently, map functions concurrently over a stream, or combine multiple streams concurrently. The README describes this as abstracting away low level details such as locks and threads.

Is streamly still being worked on?

The repository is not archived and the last push was on 2026-10-21. It publishes no GitHub releases, so version information comes from Hackage and the CHANGELOG.md file at the repository root.

Official sources

  1. composewell/streamly on GitHub
  2. Issues
  3. Project website
  4. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/composewell-streamly.svg)](https://hysenlabs.com/projects/composewell-streamly)

Star history chart for your README

markdown
[![Star history](https://hysenlabs.com/chart/composewell-streamly.svg)](https://hysenlabs.com/projects/composewell-streamly)

Was this useful?