The Best Open Source Haskell Libraries in Active Use
The Haskell ecosystem has a reputation for being hard to navigate - lots of libraries, varying maintenance states, and documentation quality that ranges from excellent to nonexistent.

The Haskell ecosystem has a reputation for being hard to navigate - lots of libraries, varying maintenance states, and documentation quality that ranges from excellent to nonexistent. Cutting through this to find the libraries that are actually worth using requires knowing which ones have stood the test of time, have active maintainers, and are relied upon by real production projects. This is a practical guide to libraries across several domains that meet that bar.
Data transformation and processing
The aeson library is the standard for JSON encoding and decoding in Haskell. It uses GHC generics to derive encoding and decoding instances automatically for custom data types - in most cases, you add two lines to your type definition and get full JSON support with no manual code. Performance is solid, error messages on decode failure are informative, and the API has been stable for years. Nearly every Haskell project that touches JSON uses aeson.
Text and ByteString are the workhorses for string handling. The text package provides Unicode-correct String handling with better performance than Haskell's built-in String type (which is a list of characters). The bytestring package handles raw binary data. Understanding when to use each - text for human-readable strings, bytestring for wire protocols and file I/O - is fundamental to writing Haskell that does not have performance problems in string-heavy code.
The containers package provides the standard data structures: Map, Set, Sequence, and IntMap. These are persistent, purely functional data structures with good asymptotic performance. They are part of the standard library ecosystem and are available in almost every Haskell project. The unordered-containers package provides HashMap and HashSet using hash-based indexing, which offers O(1) average-case operations at the cost of losing ordering properties.
Web development
Servant is the library for defining type-safe HTTP APIs. You define your API as a Haskell type - a type-level description of your endpoints, their methods, their request and response types - and Servant derives the routing, request parsing, and response serialization from that type. The compiler rejects handlers that do not match the declared API type. This eliminates an entire class of bugs where the API documentation and the implementation drift apart.
Warp is the underlying HTTP server that most Haskell web frameworks use. It is a high-performance, production-ready HTTP/1.1 and HTTP/2 server that handles tens of thousands of connections concurrently. Benchmark results consistently place it among the fastest HTTP servers across all languages. For most applications you interact with it through a higher-level library like Servant or Scotty rather than directly.
The http-client and http-conduit packages provide HTTP client functionality. http-client gives you fine-grained control over connection pooling, redirects, and request configuration. http-conduit layers streaming support on top, allowing you to process large HTTP responses without loading them entirely into memory. Both are well-maintained and handle TLS through the tls package.
Database access
Persistent is the standard ORM-like database layer in Haskell. You define your database schema as Haskell types using Template Haskell declarations, and Persistent generates the database access code, migration code, and the Haskell types that represent database rows. Backends exist for PostgreSQL, MySQL, SQLite, and MongoDB. The generated types enforce correct access - you cannot insert a value of the wrong type into a column because the Haskell type system prevents it.
For more complex queries, the Esqueleto library extends Persistent with a type-safe SQL EDSL (embedded domain-specific language). You write SQL-like code in Haskell syntax, and Esqueleto translates it to SQL. The translation is type-checked: joining tables, filtering by column, and selecting specific fields all produce type errors if you reference columns that do not exist or join tables incompatibly. This eliminates a class of bugs that string-based SQL generation makes easy to introduce.
The postgresql-simple library is the alternative for teams that prefer writing SQL directly. It provides parameterized query execution and automatic result marshaling, with the simplicity of direct SQL at the cost of the type-safety that Persistent and Esqueleto provide. Experienced SQL writers who find ORM abstractions limiting often prefer this approach.
Testing
HSpec is the standard test framework for Haskell. It provides a readable DSL for defining test cases, with nested describe blocks for organization and it blocks for individual expectations. Integration with QuickCheck - the property-based testing library - is built in, so you can mix specific example tests with property tests in the same test suite.
QuickCheck deserves special mention because it represents a different philosophy of testing than example-based tests. Instead of writing specific input-output pairs, you write properties that should hold for all inputs: sorting a list twice should give the same result as sorting it once, reversing a list twice should give the original list, encoding and then decoding a value should produce the original value. QuickCheck generates random inputs and checks that the property holds, reporting a counterexample if it finds a failure. Property-based testing catches edge cases that hand-written tests miss.
Tasty is an alternative test framework that provides a more composable architecture. Tests are values that can be combined and organized programmatically, which is useful for large test suites or suites that need to be configured differently in different environments. Both HSpec and Tasty are mature, well-maintained, and suitable for serious use.
Concurrency and parallelism
The async library provides high-level concurrency primitives. Running two actions concurrently, waiting for the first to complete, or waiting for all of a collection to complete - these patterns are expressed clearly with async, withAsync, and race. The library handles exception propagation between concurrent threads automatically, eliminating a common source of bugs in concurrent programs where an exception in one thread goes undetected.
STM (Software Transactional Memory) is built into the GHC runtime and available through the stm package. It provides composable atomic transactions over shared mutable state. The key property is composability: two STM transactions can be combined into a single atomic transaction, which is not possible with locks. STM eliminates deadlock by construction and eliminates the need to reason about lock ordering across the codebase. For complex shared state, it is substantially easier to use correctly than explicit mutexes.
Streaming and resource management
The conduit library handles streaming data processing. A conduit pipeline is a composition of producers, transformers, and consumers, where data flows from producer to consumer through the transformer chain. The pipeline is resource-safe: resources like file handles and database connections are acquired and released reliably even in the presence of exceptions. This is important for long-running stream processing where resource leaks would accumulate over time.
The resourcet package, which conduit uses internally, provides general resource management. The acquire/release pattern it implements is equivalent to bracket and finally but composes better in complex resource management scenarios. For code that needs to manage multiple resources and ensure they are all released regardless of the exit path, resourcet provides a clean abstraction.
Parsing
Megaparsec is the current recommendation for parser construction in Haskell. It provides a combinator library for building parsers from smaller parts, with excellent error messages that report the expected input at the failure point. Parsers built with Megaparsec are composable, testable, and produce informative errors - making it suitable for both simple configuration file parsing and complex language parsing.
Attoparsec is the choice when performance is the primary concern. It is faster than Megaparsec in benchmarks, at the cost of less detailed error messages. For parsing network protocols or log files at high throughput where parse errors are exceptional cases rather than user-facing feedback, Attoparsec is the appropriate tool. For most applications where developers interact with parse errors, Megaparsec's better error messages are worth the small performance cost.
More from the blog
Open Source
How the Haskell Community Builds and Maintains Its Packages
Open source package maintenance is unglamorous work. The developers who do it reliably and well enable everyone else in the...
Systems
Why Systems Programmers Are Choosing Haskell for New Projects
Systems programming has long been dominated by C, C++, and more recently Rust.
Tutorials
Understanding Type Classes in Haskell With Real Examples
Type classes are one of Haskell's most powerful and distinctive features.