Using Haskell in Production

Posted on September 8, 2025

I get asked on my stream and at talks I give, “What is it like to work in Haskell in production, full-time?”

From November of 2020 until August 2025, I was employed at Mercury where I wrote code in Haskell.

During that time I also started up a live video stream where I’ve built several libraries, games, and applications in Haskell for an audience.

This post is a summary of my experiences from those 4.5 years where I worked on a team of 20-some-odd developers writing Haskell that grew into a company with over a hundred developers. A lot of my experiences are flavoured by that unique situation. Be aware that this post is more of an experience report than a broad survey of Haskell in industry.

Let’s start with some of the trade-offs and difficulties that adopting Haskell has.

Trade Offs

Haskell has been around a long time and is a stable language and ecosystem to develop software on. However it is not a mainstream language. That is both a blessing and a curse.

Ecosystem

There is a new software service you want to integrate into your project. They publish some client SDKs. Chances are those SDKs are going to be for popular mainstream languages like Python, Go, Javascript, C++ and such. Don’t expect Haskell.

While there are open-source client libraries for many popular services such as AWS you can expect that you will be writing your own for most of them.

There are benefits to the ecosystem that make Haskell a good choice among the available functional programming languages however.

Developer Tooling

Any company with more than roughly 50-70 developers using Haskell is probably going to end up having to invest in developer tooling to some degree. “Tooling,” includes development environment integration, compiler and library improvements, performance analysis tools, and build management.

This is a difficult scale problem. Haskell isn’t a mainstream language and doesn’t enjoy an ecosystem with strong network effects forcing companies and developers to adopt it. It’s maintained by researchers, open source contributors, consultants, and a handful of companies of various sizes.

When your development team consists mostly of experienced or motivated Haskell developers the tooling available is more than sufficient. It will require some of your developers’ time to build and maintain. However they have the experience and understanding of the ecosystem and tools to hack something together.

When your development team mostly consists of people new to Haskell they’re not going to have the experience to hack together their own tools from the available options. Mentoring them to learn about all of the different options is going to be an additional burden for new hires on top of learning an unfamiliar language. You’re going to want a consistent development environment with standard tools that works well with your code base so that training these new developers doesn’t get bogged down with stringing together a custom development environment.

Compile Times

The compiler technology in GHC is astounding. It’s an excellent compiler capable of churning out efficient machine code from a very high-level language. It’s a marvel of software development.

However, GHC is doing a lot more work than most other compilers for other languages. It’s checking types, simplifying code, performing analysis and several optimizations. For small code bases of a few thousand modules this extra work is hardly noticeable and highly valuable.

However when you start using language features like Generic or Template Haskell you need to be cautious. You can easily explode your compilation times. Slow compilation times means fewer feedback loops and iterations for your developers which can impact the how frequently you can ship code.

I suspect that, for the near future, adopting Haskell for large enterprise projects is going to require a non-negligible amount of your development time to be spent on managing your build system and code tooling to manage compile times.

Run-time Introspection

The story for profiling and observing systems written in Haskell is not as mature and developed as other languages and systems like Java or C.

Like other languages that have automated resource management, Haskell can run into issues with resources at run-time. The common one being memory leaks, oddly enough, due to a build-up of un-evaluated thunks piling up on the heap. These are not always found in development before shipping a change to the production environment.

Diagnosing issues like this can some times be difficult. The tools to profile and catch these errors are available. They’re just not as sophisticated as those available in the Dot-Net, Java, and C++ ecosystems for example.

Training

The pool of Haskell developers to hire from is small. That means at some level, if your company is going to adopt Haskell, you’re going to have to be comfortable with training people. Contrast this with Javascript whose popularity eclipses Haskell’s by orders of magnitude. Companies can assume prior experience with Javascript. Even if an employee isn’t familiar with it there is so much training material available for Javascript that they could easily hit the ground running.

Companies need to be aware that they’re going to have to help train new hires in Haskell. That could be a month or two investment per employee. Unless a developer has decided to learn and use Haskell on their own chances are they haven’t encountered it.

And if you have to teach them Haskell there are limited resources to point them to. There are good books written by some bright, talented people that are great. But you will likely need someone whose familiarity and experience with Haskell can be leveraged to mentor and teach new developers.

Maintainability

Haskell has a notorious, often undeserved reputation for being a research language. This comes with the implication that it’s a “write once,” kind of language. And in some ways there’s a grain of truth to that.

It can be easy to get carried away with Haskell’s more advanced type system features. I’ve written my share of Dependent Haskell code rife with singletons and functions with more type-class constraints than arguments. You have to be careful and disciplined in using these features. A little goes a long way. And try to keep it within clearly defined boundaries so that users of your code don’t have to dig into the internals and witness the cyclopean horror you have wrought.

The more of the advanced language features you use the more training it will require from your contributors to maintain it. You want to limit this as much as you can. The features exist for a reason… try to understand those reasons and spend your innovation budget wisely.

Benefits

With the trade-offs out of the way, what has been the up-sides of programming in Haskell for a commercial enterprise?

Ecosystem

As far as functional programming languages go, Haskell has a long-standing and mature ecosystem of software packages. If you need to parse XML, connect to servers over SSH or SFTP, build a web server, add some CSRF middleware, talk to a database, parse files, etc… Haskell has you covered.

Safety

When you turn on all warnings, errors, and you use code linting, dead code analysis, and you gate your builds on all of these checks you have a system that is going to prevent a large amount of errors that are common when writing code in other languages.

You can still get the specification wrong, of course, but once you have it figured out the resulting code falls out from it in Haskell.

This also makes reviewing code much nicer in Haskell. It’s apparent where code is using side-effects. You can trust the type system. Often I only needed to read the tests and the types to understand the change well enough to approve it. This means I had to read less code and could spend more cognitive effort on reviews.

Spend Time on the Right Things

I still appreciate dynamic programming languages for what they can do and provide. But I do not miss exception traces in logs complaining about undefined methods and mismatched types. It can be handy redefining methods at run-time in order to patch code with different behaviours. But it’s a nightmare to maintain that code in the long run.

For enterprise applications Haskell makes it easy to translate requirements into code. Concepts I could discuss with analysts and customer support people would translate directly into types. And the relationships between those concepts could also be directly expressed in types. When there was an error in the business logic it showed up in the code as a type error and the program wouldn’t even compile.

I felt like I wasn’t spending much time debugging the “language” and could focus more time on business logic and solving problems.

Concurrency

I cannot sing the praises of Haskell’s concurrency story enough. GHC’s run-time is built on green-threads. It has excellent support for the STM library, async exceptions, resource management and is a delight to use.

Performance

Haskell is a very, very high level language. And yet it often produces efficient, fast code. It still has a run-time system which limits the performance you can achieve in many domains. However it’s generally well within acceptable parameters for many enterprise applications.

I worked on a team that was responsible for maintaining high-performance guarantees. When our system was too slow to respond there were financial penalties. Haskell was rarely ever the bottleneck.

In fact, Haskell helped us in some ways to manage performance. The greatest hit to such systems comes from two sources: contention and IO. The bounds of these effects were well understood in our system and it was straight-forward when reviewing code to see additions or changes which could have an impact on our performance objectives. All thanks to the separation of computation and state.

Maintainability

I’d take a spaghetti Haskell code base over a spaghetti C code base any day of the year.

One thing that separates junior developers from senior developers is sticking around long enough to live with the consequences of your decisions. I’ve had to do that with Haskell, C++, Python and even Javascript. Hands down, Haskell was the easiest to deal with.

You don’t remember every detail forever. If you don’t touch a system for six months or a year it can be hard to fill your brain back up with all the information needed to confidently make changes to that system. It still takes effort to add that knowledge back to your brain in Haskell but you have a chance to accelerate that process with Haskell because you can follow the types. You can change a type and see the consequences of that change immediately across the entire code base.

I’ve started several projects to add new features to older code with refactoring the existing code to support the new feature. In C++ or Python this would have meant writing appropriate tests to catch regressions, finding the right place in the code to make changes, make abstract interfaces, and start replacing implementations, carefully, one code path at a time. In Haskell I just change the types and fix the compiler errors one at a time until it compiles again and the tests pass. Then I can work against the new code with no abstract interfaces and indirection worming its way through the code base over time.

Even if you don’t fully understand the code you’re looking at, in Haskell, you have a chance of maintaining it.

Conclusion

When people ask me, “What is it like using Haskell in production?” they usually want me to say something that will convince others to adopt Haskell. Or they want me to say how terrible it is.

The truth is that Haskell is a programming language and like many programming languages it has strengths and has had to make a lot of interesting trade offs and choices over the years of its existence. If there was nothing to complain about it wouldn’t be a very interesting language.

When I decided to join Mercury I was in a place where I had a hunch. I had been using Haskell for small one-off projects and tools at work for a little over a year. People kept telling me that Haskell is a research language and that you can’t write serious software in it. I had to curtail and restrict my use of functional programming to keep from upsetting my colleagues too much. Functional in the sheets, procedural in the streets was the way to go. But I was never satisfied not knowing for sure since I’d never actually had a chance to take functional programming to its limits. So my hunch was that this paradigm would greatly benefit enterprise software development.

I think that hunch was right.

I’ve been programming a long, long time. I started on an Amiga with BASIC and 680x0 assembly when I was a kid. Later, I learned C then Perl, PHP, Python, Common Lisp, Javascript… and eventually toyed around with OCaml and, finally, Haskell. Languages come and go. And which language you use doesn’t usually affect outcomes in ways you might think. Haskell doesn’t instantly make all of your problems go away. I was still working with payment systems in Perl in the 90s as I was working on card transaction processing and settlement in Haskell in 2025. There are fundamental aspects to problem solving that programming languages don’t have a profound effect on.

However, it does change the way you think about solving problems, if that makes sense. Before learning Haskell my exposure to algorithms and data structures has been largely procedural, like a recipe. Functional programming has opened my mind and exposed me to different ways of thinking about programs, their structure, and how to describe them. I’m still learning and it feels like the skill ceiling is quite high here.

In the end… should you adopt Haskell?

I think that depends. Will the people you work with enjoy it? Does it provide support to you for the kinds of problems you want to tackle? Choosing what language to use for a project has a lot of implications for you down the road. You just have to get there and look back to find out if it worked well for you.