# Designing Haskell libraries for qualified import

**URL:** <https://discourse.haskell.org/t/designing-haskell-libraries-for-qualified-import/14809>\
**Category:** Links\
**Created:** [October 7, 2026, 10:46am UTC](https://discourse.haskell.org/t/designing-haskell-libraries-for-qualified-import/14809 "2026-10-07T10:46:13Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![MrcJkb](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/mrcjkb/32/2701_2.png) [@MrcJkb](https://discourse.haskell.org/u/MrcJkb)\
**Post date:** [October 7, 2026, 10:46am UTC](https://discourse.haskell.org/t/designing-haskell-libraries-for-qualified-import/14809/1 "2026-10-07T10:46:14Z")

</div>

> **[Designing Haskell libraries for qualified import](https://mrcjkb.dev/posts/2026-10-06-design-for-qualified-import.html)**
>
> Haskell development: Designing libraries for qualified import

---

<div class="post-metadata">

**Author:** ![collinarnett](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/collinarnett/32/4741_2.png) [@collinarnett](https://discourse.haskell.org/u/collinarnett)\
**Post date:** [October 7, 2026, 1:57pm UTC](https://discourse.haskell.org/t/designing-haskell-libraries-for-qualified-import/14809/2 "2026-10-07T13:57:56Z")

</div>

Ah I was also talking to @ners about this subject at NixCon. There’s also this neat little GHC option that simplifies the syntax behind these qualified import rules you listed called [require](https://theam.github.io/require/). It’s not up to date with latest GHCs and it doesn’t quite line up with your rules but maybe this can be some inspiration to standardizing the pattern.

---

<div class="post-metadata">

**Author:** ![bmobn00b](https://avatars.discourse-cdn.com/v4/letter/b/ecccb3/32.png) [@bmobn00b](https://discourse.haskell.org/u/bmobn00b)\
**Post date:** [October 7, 2026, 4:22pm UTC](https://discourse.haskell.org/t/designing-haskell-libraries-for-qualified-import/14809/3 "2026-10-07T16:22:56Z")

</div>

> **[Haskell Pattern: Design for Qualified Imports](https://jezenthomas.com/2023/08/haskell-pattern-qualified-imports/)**
>
> A simple yet thoughtful and robust convention for naming library functions in Haskell.

---

<div class="post-metadata">

**Author:** ![Kleidukos](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/kleidukos/32/1213_2.png) [@Kleidukos](https://discourse.haskell.org/u/Kleidukos)\
**Post date:** [October 7, 2026, 5:01pm UTC](https://discourse.haskell.org/t/designing-haskell-libraries-for-qualified-import/14809/4 "2026-10-07T17:01:19Z")

</div>

Great article, thanks a lot!

---

<div class="post-metadata">

**Author:** ![stevechy](https://avatars.discourse-cdn.com/v4/letter/s/c0e974/32.png) [@stevechy](https://discourse.haskell.org/u/stevechy)\
**Post date:** [October 7, 2026, 5:35pm UTC](https://discourse.haskell.org/t/designing-haskell-libraries-for-qualified-import/14809/5 "2026-10-07T17:35:43Z")

</div>

Thank you for this, I’m switching to ImportQualifiedPost.

This brings up the fact that whenever you bring in a new library you’re not sure how the imports will clash. Even a name like Span.ID could clash with something else. So I always import qualified by default with and maybe refactor later if I know the names well enough. Sometimes with a new library it helps to just convert the unqualified import tutorial code to qualified imports so that you know what is where.

The other thing is that if you only work on a codebase occaisionally you might forget if you import it as Span.ID or ID when you come back to it and then you start a new file with a different import name.

At first I thought that a solution might be to allow the module to define a default alias name but now I feel like maybe it’s best if there could be a file in the project that keeps track of import names.

So if I can put `import Effectful.OpenTelemetry.Tracing.Span.ID qualified as Span.ID` in one file and then in the rest of the code use `import Span.ID qualified`. Then at least if some other library uses `Span.ID` I can add `import OtherLibrary.Span.ID qualified as OtherSpan.Id` in the imports file.

---

<div class="post-metadata">

**Author:** ![bmobn00b](https://avatars.discourse-cdn.com/v4/letter/b/ecccb3/32.png) [@bmobn00b](https://discourse.haskell.org/u/bmobn00b)\
**Post date:** [October 7, 2026, 6:06pm UTC](https://discourse.haskell.org/t/designing-haskell-libraries-for-qualified-import/14809/6 "2026-10-07T18:06:04Z")

</div>

And I believe @taylorfausak is a huge fan of qualified imports. I was amazed when I read the source code of [cabal-gild](https://github.com/tfausak/cabal-gild/blob/df85a19/source/library/CabalGild/Unstable/Main.hs).

---

<div class="post-metadata">

**Author:** ![taylorfausak](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/taylorfausak/32/54_2.png) [@taylorfausak](https://discourse.haskell.org/u/taylorfausak)\
**Post date:** [October 7, 2026, 7:27pm UTC](https://discourse.haskell.org/t/designing-haskell-libraries-for-qualified-import/14809/7 "2026-10-07T19:27:17Z")

</div>

Indeed I am! Qualified imports are the best. I even built [Imp](https://hackage.haskell.org/package/imp-1.0.3.5), a GHC plugin for automatically importing modules based on qualified usage.

---

<div class="post-metadata">

**Author:** ![jackdk](https://avatars.discourse-cdn.com/v4/letter/j/9f8e36/32.png) [@jackdk](https://discourse.haskell.org/u/jackdk)\
**Post date:** [October 8, 2026, 2:31am UTC](https://discourse.haskell.org/t/designing-haskell-libraries-for-qualified-import/14809/8 "2026-10-08T02:31:22Z")

</div>

I’m also a fan.

> **[Design modules for qualified import - Some Haskell idioms we like](https://exploring-better-ways.bellroy.com/some-haskell-idioms-we-like.html#design-modules-for-qualified-import)**
>
> Scaling up our Haskell usage at Bellroy has meant cultivating a “house style” or “engineering dialect”. While a house style obviously means making decisions about the traditional Haskell decision points --- choosing a preferred set of libraries and...

---

<div class="post-metadata">

**Author:** ![tomjaguarpaw](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/tomjaguarpaw/32/1230_2.png) [@tomjaguarpaw](https://discourse.haskell.org/u/tomjaguarpaw)\
**Post date:** [October 8, 2026, 7:06am UTC](https://discourse.haskell.org/t/designing-haskell-libraries-for-qualified-import/14809/9 "2026-10-08T07:06:37Z")

</div>

This is basically the style I like to use. Thanks for writing it up!

---

<div class="post-metadata">

**Author:** ![superstar64](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/superstar64/32/5308_2.png) [@superstar64](https://discourse.haskell.org/u/superstar64)\
**Post date:** [October 8, 2026, 2:46pm UTC](https://discourse.haskell.org/t/designing-haskell-libraries-for-qualified-import/14809/10 "2026-10-08T14:46:59Z")

</div>

So colloquially call this Java style Haskell and I follow this very heavy in [Hazy](https://github.com/superstar64/hazy). I’m pretty happy with the result, I rarely ever have name conflicts and I think the end result is pretty readable.

Let me talk about my major issue I’ve run into following philosophy and that is `.hs-boot` hell. Anytime I need types or functions there are mutually recursive, I need to painfully create new `.hs-boot` modules. Sometimes I even need to reorganize my code because the resulting hs-boot files would be mutually recursive (see [There are mutually recursive programs that GHC can't compile](https://discourse.haskell.org/t/there-are-mutually-recursive-programs-that-ghc-cant-compile/14316)). For reference I currently I have 445 normal Haskell files and 95 `.hs-boot` modules, so 20% of my modules need `.hs-boot` files (this could probably be reduced).

Still, even with this major problem, I think the end result is much better then alternative.
