diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,11 @@
 The format is based on [Keep a Changelog](http://keepachangelog.com/)
 and this project adheres to [Semantic Versioning](http://semver.org/).
 
+## [0.6.5] - 2021-06-26
+
+- yarn-lock: Remove `protolude` dependency in order to add to `stackage`.
+- Relax upper bound of `hnix`.
+
 ## [0.6.4] - 2021-03-30
 
 - Repository changed to https://github.com/Profpatsch/yarn2nix
diff --git a/src/Data/MultiKeyedMap.hs b/src/Data/MultiKeyedMap.hs
--- a/src/Data/MultiKeyedMap.hs
+++ b/src/Data/MultiKeyedMap.hs
@@ -27,7 +27,6 @@
 
 import qualified Data.Map.Strict as M
 import Data.Monoid (All(..))
-import Data.Semigroup ((<>))
 import Data.Foldable (foldl')
 import qualified Data.List.NonEmpty as NE
 import Data.Proxy (Proxy(..))
diff --git a/src/Yarn/Lock.hs b/src/Yarn/Lock.hs
--- a/src/Yarn/Lock.hs
+++ b/src/Yarn/Lock.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE NoImplicitPrelude, LambdaCase, OverloadedStrings, RecordWildCards #-}
+{-# LANGUAGE LambdaCase, OverloadedStrings, RecordWildCards #-}
 {-|
 Module : Yarn.Lock
 Description : High-level parser of yarn.lock files
@@ -18,8 +18,6 @@
 , LockfileError(..), PackageErrorInfo(..)
 ) where
 
-import Protolude hiding ((<>))
-import Data.Semigroup ((<>))
 import qualified Data.Text as T
 import qualified Data.List.NonEmpty as NE
 import qualified Text.Megaparsec as MP
@@ -28,6 +26,12 @@
 import qualified Yarn.Lock.Types as T
 import qualified Yarn.Lock.File as File
 import qualified Yarn.Lock.Parse as Parse
+import Data.Text (Text)
+import Data.Functor ((<&>))
+import Control.Monad ((>=>))
+import qualified Data.Text as Text
+import qualified Data.Text.IO as Text.IO
+import Data.Bifunctor (first, Bifunctor (bimap))
 
 -- | Everything that can go wrong when parsing a 'Lockfile'.
 data LockfileError
@@ -51,7 +55,7 @@
 -- see 'File.fromPackages'.
 parseFile :: FilePath -- ^ file to read
           -> IO (Either LockfileError T.Lockfile)
-parseFile fp = readFile fp >>= pure . parse fp
+parseFile fp = Text.IO.readFile fp <&> parse fp
 
 -- | For when you want to provide only the file contents.
 parse :: FilePath -- ^ name of the input file, used for the parser
@@ -65,12 +69,12 @@
   (ParseError t) -> "Error while parsing the yarn.lock:\n"
     <> T.unlines (indent 2 (T.lines t))
   (PackageErrors errs) -> "Some packages could not be made sense of:\n"
-    <> T.unlines (NE.toList $ indent 2 (join $ fmap errText errs))
+    <> T.unlines (NE.toList $ indent 2 (errs >>= errText))
   where
     indent :: Functor f => Int -> f Text -> f Text
     indent i = fmap (T.replicate i " " <>)
-    errText (PackageErrorInfo{..}) =
-      (pure $ "Package at " <> (toS $ MP.sourcePosPretty srcPos) <> ":")
+    errText PackageErrorInfo{..} =
+      (pure $ "Package at " <> (Text.pack $ MP.sourcePosPretty srcPos) <> ":")
       <> indent 2 (fmap convErrText convErrs)
     convErrText = \case
       (File.MissingField t) -> "Field " <> qu t <> " is missing."
@@ -81,7 +85,7 @@
 
 -- helpers
 astParse :: FilePath -> Text -> Either LockfileError [Parse.Package]
-astParse fp = first (ParseError . toS . MP.errorBundlePretty)
+astParse fp = first (ParseError . Text.pack . MP.errorBundlePretty)
                 . MP.parse Parse.packageList fp
 
 toPackages :: [Parse.Package] -> Either LockfileError [T.Keyed T.Package]
diff --git a/src/Yarn/Lock/File.hs b/src/Yarn/Lock/File.hs
--- a/src/Yarn/Lock/File.hs
+++ b/src/Yarn/Lock/File.hs
@@ -12,7 +12,8 @@
 (like for example sum types), so information like e.g.
 the remote type have to be inferred frome AST values.
 -}
-{-# LANGUAGE NoImplicitPrelude, OverloadedStrings, ApplicativeDo, RecordWildCards, NamedFieldPuns #-}
+{-# LANGUAGE OverloadedStrings, ApplicativeDo, RecordWildCards, NamedFieldPuns #-}
+{-# LANGUAGE LambdaCase #-}
 module Yarn.Lock.File
 ( fromPackages
 , astToPackage
@@ -20,7 +21,6 @@
 , ConversionError(..)
 ) where
 
-import Protolude hiding (hash, getField)
 import qualified Data.List.NonEmpty as NE
 import qualified Data.Map.Strict as M
 import qualified Data.Text as Text
@@ -29,6 +29,13 @@
 import qualified Yarn.Lock.Parse as Parse
 import qualified Yarn.Lock.Types as T
 import qualified Data.MultiKeyedMap as MKM
+import Data.Text (Text)
+import Data.Bifunctor (first)
+import Control.Monad ((>=>))
+import Control.Applicative ((<|>))
+import Data.Maybe (fromMaybe)
+import Data.Either.Validation (Validation(Success, Failure))
+import Data.Traversable (for)
 
 -- | Press a list of packages into the lockfile structure.
 --
@@ -86,9 +93,11 @@
           Nothing -> case mopt of
             Just opt -> Right opt
             Nothing  -> Left $ MissingField fieldName
-          Just val -> note
-            (WrongType { fieldName, fieldType = parserName typeParser })
-            $ parseField typeParser val
+          Just val ->
+            case parseField typeParser val of
+              Nothing -> Left
+                (WrongType { fieldName, fieldType = parserName typeParser })
+              Just a -> Right a
 
     -- | Parse a simple field to type 'Text'.
     text :: FieldParser Text
@@ -123,9 +132,13 @@
         $ checkGit <|> checkFileLocal <|> checkFile
       where
         mToV :: e -> Maybe a -> V.Validation e a
-        mToV err = V.eitherToValidation . note err
+        mToV err mb = case mb of
+          Nothing -> Failure err
+          Just a -> Success a
         vToM :: Val a -> Maybe a
-        vToM = hush . V.validationToEither
+        vToM = \case
+          Success a -> Just a
+          Failure _err -> Nothing
 
         -- | "https://blafoo.com/a/b#alonghash"
         --   -> ("https://blafoo.com/a/b", "alonghash")
@@ -135,7 +148,7 @@
           [url']       -> (url', Nothing)
           [url', ""]   -> (url', Nothing)
           [url', hash] -> (url', Just hash)
-          _           -> panic "checkRemote: # should only appear exactly once!"
+          _           -> error "checkRemote: # should only appear exactly once!"
 
         checkGit :: Maybe T.Remote
         checkGit = do
@@ -172,4 +185,4 @@
 
         -- | ensure the prefix is removed
         noPrefix :: Text -> Text -> Text
-        noPrefix pref hay = maybe hay identity $ Text.stripPrefix pref hay
+        noPrefix pref hay = fromMaybe hay $ Text.stripPrefix pref hay
diff --git a/src/Yarn/Lock/Helpers.hs b/src/Yarn/Lock/Helpers.hs
--- a/src/Yarn/Lock/Helpers.hs
+++ b/src/Yarn/Lock/Helpers.hs
@@ -1,4 +1,3 @@
-{-# LANGUAGE NoImplicitPrelude #-}
 {-|
 Module : Yarn.Lock.Helpers
 Description : Helpers for modifying Lockfiles
@@ -13,13 +12,13 @@
 ( decycle
 ) where
 
-import Protolude
 import qualified Data.List as L
 import GHC.Stack (HasCallStack)
 
 import qualified Data.MultiKeyedMap as MKM
 
 import Yarn.Lock.Types
+import Data.Foldable (foldl')
 
 
 -- | Takes a 'Lockfile' and removes dependency cycles.
@@ -52,4 +51,5 @@
                                , optionalDependencies = newOptDeps }) lf'
       -- finally we do the same for all remaining deps
       in goFold seen lf'' $ newDeps ++ newOptDeps
-    go [] _ = panic $ toS "should not happen!"
+    go [] _ = error "should not happen!"
+
diff --git a/src/Yarn/Lock/Parse.hs b/src/Yarn/Lock/Parse.hs
--- a/src/Yarn/Lock/Parse.hs
+++ b/src/Yarn/Lock/Parse.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE NoImplicitPrelude, GeneralizedNewtypeDeriving, OverloadedStrings #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving, OverloadedStrings #-}
 {-|
 Module : Yarn.Lock.Parse
 Description : Parser for yarn.lock files
@@ -20,12 +20,11 @@
 , packageKeys
 ) where
 
-import Protolude hiding (try, some, many)
 import qualified Data.Char as Ch
 import qualified Data.List.NonEmpty as NE
 import qualified Data.Text as T
 import qualified Data.Map.Strict as M
-import Control.Monad (fail)
+import Control.Monad (void)
 
 import Text.Megaparsec as MP
 import qualified Text.Megaparsec.Char as MP
@@ -35,6 +34,10 @@
 -- import Data.Proxy (Proxy(..))
 
 import qualified Yarn.Lock.Types as YLT
+import Data.Text (Text)
+import Data.Void (Void)
+import Data.Map.Strict (Map)
+import qualified Data.Text as Text
 
 
 -- | We use a simple (pure) @Megaparsec@ parser.
@@ -130,7 +133,7 @@
     emptyKeyErr :: Text -> Parser a
     emptyKeyErr key = fail
       ("packagekey: package name can not be empty (is: "
-      <> toS key <> ")")
+      <> Text.unpack key <> ")")
 
     -- | Like 'T.breakOn', but drops the separator char.
     breakDrop :: Char -> Text -> (Text, Text)
@@ -141,7 +144,7 @@
     -- | Parses a (scoped) package key and throws an error if misformatted.
     scoped n = maybe
       (fail $ "packageKey: scoped variable must be of form @scope/package"
-           <> " (is: " <> toS n <> ")")
+           <> " (is: " <> Text.unpack n <> ")")
       pure $ YLT.parsePackageKeyName n
 
 -- | Either a simple or a nested field.
@@ -192,7 +195,7 @@
     toPfs = PackageFields . M.fromList
 
 -- | Characters allowed in key symbols.
--- 
+--
 -- TODO: those are partly npm package names, so check the allowed symbols, too.
 --
 -- Update: npm doesn’t specify the package name format, at all.
diff --git a/src/Yarn/Lock/Types.hs b/src/Yarn/Lock/Types.hs
--- a/src/Yarn/Lock/Types.hs
+++ b/src/Yarn/Lock/Types.hs
@@ -7,10 +7,11 @@
 -}
 module Yarn.Lock.Types where
 
-import Protolude hiding (try)
-import qualified Data.Text as T
 import qualified Data.MultiKeyedMap as MKM
 import qualified Data.List.NonEmpty as NE
+import Data.Data (Proxy (Proxy))
+import Data.Text (Text)
+import qualified Data.Text as Text
 
 -- | Yarn lockfile.
 --
@@ -44,11 +45,11 @@
 
 -- | Try to parse a string into a package key name (scoped or not).
 parsePackageKeyName :: Text -> Maybe PackageKeyName
-parsePackageKeyName n = case T.stripPrefix "@" n of
+parsePackageKeyName n = case Text.stripPrefix "@" n of
   Nothing -> Just $ SimplePackageKey n
-  Just sc -> case T.breakOn "/" sc of
+  Just sc -> case Text.breakOn "/" sc of
     (_, "") -> Nothing
-    (scope, pkg) -> Just $ ScopedPackageKey scope (T.drop 1 pkg)
+    (scope, pkg) -> Just $ ScopedPackageKey scope (Text.drop 1 pkg)
 
 -- | Something with a list of 'PackageKey's pointing to it.
 data Keyed a = Keyed (NE.NonEmpty PackageKey) a
diff --git a/tests/TestFile.hs b/tests/TestFile.hs
--- a/tests/TestFile.hs
+++ b/tests/TestFile.hs
@@ -1,7 +1,6 @@
-{-# LANGUAGE OverloadedStrings, TemplateHaskell, NamedFieldPuns, ViewPatterns, NoImplicitPrelude, LambdaCase, RecordWildCards #-}
+{-# LANGUAGE OverloadedStrings, TemplateHaskell, NamedFieldPuns, ViewPatterns, LambdaCase, RecordWildCards #-}
 module TestFile (tests) where
 
-import Protolude
 import qualified Data.List.NonEmpty as NE
 import Test.Tasty (TestTree)
 import Test.Tasty.TH
@@ -11,6 +10,9 @@
 import qualified Yarn.Lock.Types as T
 import qualified Yarn.Lock.File as File
 import qualified Yarn.Lock.Parse as Parse
+import Data.Text (Text)
+import Data.Functor ((<&>))
+import Control.Applicative (Alternative (empty))
 
 -- TODO: actually use somehow (apart from manual testing)
 -- The yarn.lock file should resolve each packageKey exactly once.
@@ -94,7 +96,7 @@
 astToPackageSuccess ast = case File.astToPackage ast of
   (Left errs) -> do
      _ <- assertFailure ("should have succeded, but:\n" <> show errs)
-     panic "not reached"
+     error "not reached"
   (Right pkg) -> pure pkg
 
 astToPackageFailureWith :: (NE.NonEmpty File.ConversionError)
@@ -174,3 +176,6 @@
 tests :: TestTree
 tests = $(testGroupGenerator)
 
+
+orEmpty :: Alternative f => Bool -> a -> f a
+orEmpty b a = if b then pure a else empty
diff --git a/tests/TestMultiKeyedMap.hs b/tests/TestMultiKeyedMap.hs
--- a/tests/TestMultiKeyedMap.hs
+++ b/tests/TestMultiKeyedMap.hs
@@ -1,7 +1,6 @@
-{-# LANGUAGE OverloadedStrings, TemplateHaskell, QuasiQuotes, NamedFieldPuns, ViewPatterns, NoImplicitPrelude #-}
+{-# LANGUAGE OverloadedStrings, TemplateHaskell, QuasiQuotes, NamedFieldPuns, ViewPatterns #-}
 module TestMultiKeyedMap (tests) where
 
-import Protolude
 import qualified Data.List as List
 import qualified Data.List.NonEmpty as NE
 import Test.Tasty (TestTree)
@@ -10,6 +9,9 @@
 import Test.QuickCheck.Instances () -- orphans!
 
 import qualified Data.MultiKeyedMap as MKM
+import Data.Data (Proxy (Proxy))
+import Data.Function (on)
+import Data.Foldable (foldl')
 
 emptyMkm :: (Ord k) => MKM.MKMap k v
 emptyMkm = MKM.mkMKMap (Proxy :: Proxy Int)
diff --git a/tests/TestParse.hs b/tests/TestParse.hs
--- a/tests/TestParse.hs
+++ b/tests/TestParse.hs
@@ -1,7 +1,6 @@
-{-# LANGUAGE OverloadedStrings, TemplateHaskell, QuasiQuotes, NamedFieldPuns, ViewPatterns, NoImplicitPrelude #-}
+{-# LANGUAGE OverloadedStrings, TemplateHaskell, QuasiQuotes, NamedFieldPuns, ViewPatterns #-}
 module TestParse (tests) where
 
-import Protolude
 import qualified Data.Map as Map
 import qualified Data.List.NonEmpty as NE
 import Test.Tasty (TestTree)
@@ -13,6 +12,9 @@
 
 import Yarn.Lock.Types
 import Yarn.Lock.Parse
+import Data.Text (Text)
+import qualified Data.Text as Text
+import Control.Monad (void)
 
 startComment :: Text
 startComment = [text|
@@ -71,13 +73,13 @@
 
 case_NestedPackage :: Assertion
 case_NestedPackage = do
-  assertBool "there is unicode" (all Ch.isAscii (toS nestedPackageExample :: [Char]))
+  assertBool "there is unicode" (all Ch.isAscii (Text.unpack nestedPackageExample :: [Char]))
   parseSuccess packageEntry nestedPackageExample
     >>= \(Keyed _ (_, PackageFields fields)) -> do
       case Map.lookup "dependencies" fields of
         (Nothing) -> assertFailure "where’s the key"
         (Just (Left s)) -> do
-          assertFailure $ toS (s <> "should be a nested package")
+          assertFailure $ Text.unpack (s <> "should be a nested package")
         (Just (Right (PackageFields nested))) -> do
           assertEqual "nested keys" 4 $ length nested
           assertEqual "dep exists" (Just (Left "2.3.4"))
@@ -143,8 +145,8 @@
     (Left err) -> do
       _ <- assertFailure ("parse should succeed, but: \n"
                     <> MP.errorBundlePretty err
-                    <> "for input\n" <> toS string <> "\n\"")
-      panic "not reached"
+                    <> "for input\n" <> Text.unpack string <> "\n\"")
+      error "not reached"
 
 parseFailure :: Parser a -> Text -> IO ()
 parseFailure parser string = do
diff --git a/yarn-lock.cabal b/yarn-lock.cabal
--- a/yarn-lock.cabal
+++ b/yarn-lock.cabal
@@ -5,7 +5,7 @@
 -- see: https://github.com/sol/hpack
 
 name:           yarn-lock
-version:        0.6.4
+version:        0.6.5
 synopsis:       Represent and parse yarn.lock files
 description:    Types and parser for the lock file format of the npm successor yarn. All modules should be imported qualified.
 category:       Data
@@ -41,7 +41,6 @@
     , containers
     , either >=4 && <6
     , megaparsec >=7 && <10
-    , protolude >=0.2 && <0.4
     , text
   default-language: Haskell2010
 
@@ -63,7 +62,6 @@
     , either >=4 && <6
     , megaparsec >=7 && <10
     , neat-interpolation >=0.3
-    , protolude
     , quickcheck-instances ==0.3.*
     , tasty >=0.11
     , tasty-hunit >=0.9
