diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,9 @@
 ## Changelog for Weeder
 
+### [`2.3.0`][v2.3.0] - *2021-10-11*
+
+- Switch to GHC 9
+
 ### [`2.2.0`][v2.2.0] - *2021-08-28*
 
 This will likely be the last Weeder release before GHC 9.
@@ -197,6 +201,7 @@
 - Initial version
 
 
+[v2.3.0 ]: https://github.com/ocharles/weeder/releases/tag/2.3.0
 [v2.2.0 ]: https://github.com/ocharles/weeder/releases/tag/2.2.0
 [v2.1.3 ]: https://github.com/ocharles/weeder/releases/tag/2.1.3
 [v2.1.2 ]: https://github.com/ocharles/weeder/releases/tag/2.1.2
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -83,29 +83,11 @@
 
 ``` shell
 $ weeder
-
-src/Dhall/TH.hs:187:1: error: toDeclaration is unused
-
-     185 ┃     -> HaskellType (Expr s a)
-     186 ┃     -> Q Dec
-     187 ┃ toDeclaration haskellTypes MultipleConstructors{..} = do
-     188 ┃     case code of
-     189 ┃         Union kts -> do
-
-    Delete this definition or add ‘Dhall.TH.toDeclaration’ as a root to fix this error.
-
-
-src/Dhall/TH.hs:106:1: error: toNestedHaskellType is unused
-
-     104 ┃     -- ^ Dhall expression to convert to a simple Haskell type
-     105 ┃     -> Q Type
-     106 ┃ toNestedHaskellType haskellTypes = loop
-     107 ┃   where
-     108 ┃     loop dhallType = case dhallType of
-
-    Delete this definition or add ‘Dhall.TH.toNestedHaskellType’ as a root to fix this error.
+src/Dhall/TH.hs:187: toDeclaration
+src/Dhall/TH.hs:196: toNestedHaskellType
 ```
 
+… which indicates the location of two unused symbols.
 (Please note these warnings are just for demonstration and not necessarily weeds
 in the Dhall project).
 
diff --git a/exe-weeder/Main.hs b/exe-weeder/Main.hs
--- a/exe-weeder/Main.hs
+++ b/exe-weeder/Main.hs
@@ -1,2 +1,8 @@
 module Main ( main ) where
-import Weeder.Main
+
+-- weeder
+import qualified Weeder.Main
+
+
+main :: IO ()
+main = Weeder.Main.main
diff --git a/src/Weeder.hs b/src/Weeder.hs
--- a/src/Weeder.hs
+++ b/src/Weeder.hs
@@ -48,23 +48,24 @@
 import Data.Generics.Labels ()
 
 -- ghc
-import Avail ( AvailInfo( Avail, AvailTC ) )
-import FieldLabel ( FieldLbl( FieldLabel, flSelector ) )
-import HieTypes
+import GHC.Types.Avail ( AvailInfo( Avail, AvailTC ) )
+import GHC.Types.FieldLabel ( FieldLbl( FieldLabel, flSelector ) )
+import GHC.Iface.Ext.Types
   ( BindType( RegularBind )
   , ContextInfo( Decl, ValBind, PatternBind, Use, TyDecl, ClassTyDecl )
   , DeclType( DataDec, ClassDec, ConDec )
-  , HieAST( Node, nodeInfo, nodeChildren, nodeSpan )
+  , HieAST( Node, nodeChildren, nodeSpan, sourcedNodeInfo )
   , HieASTs( HieASTs )
   , HieFile( HieFile, hie_asts, hie_exports, hie_module, hie_hs_file )
   , IdentifierDetails( IdentifierDetails, identInfo )
-  , NodeInfo( NodeInfo, nodeIdentifiers, nodeAnnotations )
+  , NodeInfo( nodeIdentifiers, nodeAnnotations )
   , Scope( ModuleScope )
+  , getSourcedNodeInfo
   )
-import Module ( Module, moduleStableString )
-import Name ( Name, nameModule_maybe, nameOccName )
-import OccName
-  ( OccName
+import GHC.Unit.Module ( Module, moduleStableString )
+import GHC.Types.Name
+  ( Name, nameModule_maybe, nameOccName
+  , OccName
   , isDataOcc
   , isDataSymOcc
   , isTcOcc
@@ -72,7 +73,7 @@
   , isVarOcc
   , occNameString
   )
-import SrcLoc ( RealSrcSpan, realSrcSpanEnd, realSrcSpanStart )
+import GHC.Types.SrcLoc ( RealSrcSpan, realSrcSpanEnd, realSrcSpanStart )
 
 -- lens
 import Control.Lens ( (%=) )
@@ -262,8 +263,8 @@
 
 
 analyseBinding :: ( Alternative m, MonadState Analysis m ) => HieAST a -> m ()
-analyseBinding n@Node{ nodeSpan, nodeInfo = NodeInfo{ nodeAnnotations } } = do
-  guard $ ( "FunBind", "HsBindLR" ) `Set.member` nodeAnnotations
+analyseBinding n@Node{ nodeSpan, sourcedNodeInfo } = do
+  guard $ any (Set.member ("FunBind", "HsBindLR") . nodeAnnotations) $ getSourcedNodeInfo sourcedNodeInfo
 
   for_ ( findDeclarations n ) \d -> do
     define d nodeSpan
@@ -272,22 +273,22 @@
 
 
 analyseRewriteRule :: ( Alternative m, MonadState Analysis m ) => HieAST a -> m ()
-analyseRewriteRule n@Node{ nodeInfo = NodeInfo{ nodeAnnotations } } = do
-  guard ( ( "HsRule", "RuleDecl" ) `Set.member` nodeAnnotations )
+analyseRewriteRule n@Node{ sourcedNodeInfo } = do
+  guard $ any (Set.member ("HsRule", "RuleDecl") . nodeAnnotations) $ getSourcedNodeInfo sourcedNodeInfo
 
   for_ ( uses n ) addImplicitRoot
 
 
 analyseInstanceDeclaration :: ( Alternative m, MonadState Analysis m ) => HieAST a -> m ()
-analyseInstanceDeclaration n@Node{ nodeInfo = NodeInfo{ nodeAnnotations } } = do
-  guard ( ( "ClsInstD", "InstDecl" ) `Set.member` nodeAnnotations )
+analyseInstanceDeclaration n@Node{ sourcedNodeInfo } = do
+  guard $ any (Set.member ("ClsInstD", "InstDecl") . nodeAnnotations) $ getSourcedNodeInfo sourcedNodeInfo
 
   traverse_ addImplicitRoot ( uses n )
 
 
 analyseClassDeclaration :: ( Alternative m, MonadState Analysis m ) => HieAST a -> m ()
-analyseClassDeclaration n@Node{ nodeInfo = NodeInfo{ nodeAnnotations } } = do
-  guard ( ( "ClassDecl", "TyClDecl" ) `Set.member` nodeAnnotations )
+analyseClassDeclaration n@Node{ sourcedNodeInfo } = do
+  guard $ any (Set.member ("ClassDecl", "TyClDecl") . nodeAnnotations) $ getSourcedNodeInfo sourcedNodeInfo
 
   for_ ( findIdentifiers isClassDeclaration n ) $
     for_ ( findIdentifiers ( const True ) n ) . addDependency
@@ -304,8 +305,8 @@
 
 
 analyseDataDeclaration :: ( Alternative m, MonadState Analysis m ) => HieAST a -> m ()
-analyseDataDeclaration n@Node { nodeInfo = NodeInfo{ nodeAnnotations } } = do
-  guard ( ( "DataDecl", "TyClDecl" ) `Set.member` nodeAnnotations )
+analyseDataDeclaration n@Node{ sourcedNodeInfo } = do
+  guard $ any (Set.member ("DataDecl", "TyClDecl") . nodeAnnotations) $ getSourcedNodeInfo sourcedNodeInfo
 
   for_
     ( foldMap
@@ -331,16 +332,16 @@
 
 
 constructors :: HieAST a -> Seq ( HieAST a )
-constructors n@Node { nodeChildren, nodeInfo = NodeInfo{ nodeAnnotations } } =
-  if any ( \( _, t ) -> t == "ConDecl" ) nodeAnnotations then
+constructors n@Node{ nodeChildren, sourcedNodeInfo } =
+  if any (any (\( _, t) -> t == "ConDecl" ) . nodeAnnotations) (getSourcedNodeInfo sourcedNodeInfo) then
     pure n
 
   else
     foldMap constructors nodeChildren
 
 analysePatternSynonyms :: ( Alternative m, MonadState Analysis m ) => HieAST a -> m ()
-analysePatternSynonyms n@Node{ nodeInfo = NodeInfo{ nodeAnnotations } } = do
-  guard $ ( "PatSynBind", "HsBindLR" ) `Set.member` nodeAnnotations
+analysePatternSynonyms n@Node{ sourcedNodeInfo } = do
+  guard $ any (Set.member ("PatSynBind", "HsBindLR") . nodeAnnotations) $ getSourcedNodeInfo sourcedNodeInfo
 
   for_ ( findDeclarations n ) $ for_ ( uses n ) . addDependency
 
@@ -366,7 +367,7 @@
   :: ( Set ContextInfo -> Bool )
   -> HieAST a
   -> Seq Declaration
-findIdentifiers f Node{ nodeInfo = NodeInfo{ nodeIdentifiers }, nodeChildren } =
+findIdentifiers f Node{ sourcedNodeInfo, nodeChildren } =
      foldMap
        ( \case
            ( Left _, _ ) ->
@@ -379,8 +380,7 @@
              else
                mempty
            )
-
-       ( Map.toList nodeIdentifiers )
+       (foldMap (Map.toList . nodeIdentifiers) (getSourcedNodeInfo sourcedNodeInfo))
   <> foldMap ( findIdentifiers f ) nodeChildren
 
 
diff --git a/src/Weeder/Main.hs b/src/Weeder/Main.hs
--- a/src/Weeder/Main.hs
+++ b/src/Weeder/Main.hs
@@ -35,13 +35,13 @@
 import System.FilePath ( isExtensionOf )
 
 -- ghc
-import HieBin ( HieFileResult( HieFileResult, hie_file_result ), readHieFileWithVersion )
-import HieTypes ( HieFile( hie_hs_file ), hieVersion )
-import Module ( moduleName, moduleNameString )
-import NameCache ( initNameCache, NameCache )
-import OccName ( occNameString )
-import SrcLoc ( RealSrcLoc, realSrcSpanStart, srcLocLine )
-import UniqSupply ( mkSplitUniqSupply )
+import GHC.Iface.Ext.Binary ( HieFileResult( HieFileResult, hie_file_result ), NameCacheUpdater( NCU ), readHieFileWithVersion )
+import GHC.Iface.Ext.Types ( HieFile( hie_hs_file ), hieVersion )
+import GHC.Unit.Module ( moduleName, moduleNameString )
+import GHC.Types.Name.Cache ( initNameCache, NameCache )
+import GHC.Types.Name ( occNameString )
+import GHC.Types.SrcLoc ( RealSrcLoc, realSrcSpanStart, srcLocLine )
+import GHC.Types.Unique.Supply ( mkSplitUniqSupply )
 
 -- regex-tdfa
 import Text.Regex.TDFA ( (=~) )
@@ -218,9 +218,9 @@
 -- | Read a .hie file, exiting if it's an incompatible version.
 readCompatibleHieFileOrExit :: NameCache -> FilePath -> IO HieFile
 readCompatibleHieFileOrExit nameCache path = do
-  res <- readHieFileWithVersion (\ (v, _) -> v == hieVersion) nameCache path
+  res <- readHieFileWithVersion (\(v, _) -> v == hieVersion) (NCU (\f -> return $ snd $ f nameCache)) path
   case res of
-    Right ( HieFileResult{ hie_file_result }, _ ) ->
+    Right HieFileResult{ hie_file_result } ->
       return hie_file_result
     Left ( v, _ghcVersion ) -> do
       putStrLn $ "incompatible hie file: " <> path
@@ -241,3 +241,4 @@
 (==>) :: Bool -> Bool -> Bool
 True  ==> x = x
 False ==> _ = True
+
diff --git a/weeder.cabal b/weeder.cabal
--- a/weeder.cabal
+++ b/weeder.cabal
@@ -5,7 +5,7 @@
 author:        Ollie Charles <ollie@ocharles.org.uk>
 maintainer:    Ollie Charles <ollie@ocharles.org.uk>
 build-type:    Simple
-version:       2.2.0
+version:       2.3.0
 copyright:     Neil Mitchell 2017-2020, Oliver Charles 2020
 synopsis:      Detect dead code
 description:   Find declarations.
@@ -19,14 +19,14 @@
 library
   build-depends:
     , algebraic-graphs     ^>= 0.4 || ^>= 0.5
-    , base                 ^>= 4.13.0.0 || ^>= 4.14.0.0
+    , base                 ^>= 4.15.0.0
     , bytestring           ^>= 0.10.9.0 || ^>= 0.11.0.0
     , containers           ^>= 0.6.2.1
     , dhall                ^>= 1.30.0 || ^>= 1.31.0 || ^>= 1.32.0 || ^>= 1.33.0 || ^>= 1.34.0 || ^>= 1.35.0 || ^>= 1.36.0 || ^>= 1.37.0 || ^>= 1.40.0
     , directory            ^>= 1.3.3.2
     , filepath             ^>= 1.4.2.1
-    , generic-lens         ^>= 1.1.0.0 || ^>= 1.2.0.0 || ^>= 2.0.0.0 || ^>= 2.2.0.0
-    , ghc                  ^>= 8.8.1 || ^>= 8.10
+    , generic-lens         ^>= 2.2.0.0
+    , ghc                  ^>= 9.0
     , lens                 ^>= 4.18.1 || ^>= 4.19 || ^>= 5.0.1
     , mtl                  ^>= 2.2.2
     , optparse-applicative ^>= 0.14.3.0 || ^>= 0.15.1.0 || ^>= 0.16.0.0
