diff --git a/CHANGES.markdown b/CHANGES.markdown
--- a/CHANGES.markdown
+++ b/CHANGES.markdown
@@ -1,3 +1,6 @@
+Changes in 0.21.0
+  - Accept `--fast`, `--preserve-it` and `--verbose` via `--repl-options`
+
 Changes in 0.20.1
   - GHC 9.4 compatibility. (#382)
 
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -10,7 +10,8 @@
 * [Getting started](#getting-started)
    * [Installation](#installation)
    * [A basic example](#a-basic-example)
-   * [Running doctest for a Cabal package](#running-doctest-for-a-cabal-package)
+* [Running doctest for a Cabal package](#running-doctest-for-a-cabal-package)
+   * [Passing doctest options to cabal repl](#passing-doctest-options-to-cabal-repl)
 * [Writing examples and properties](#writing-examples-and-properties)
    * [Example groups](#example-groups)
       * [A note on performance](#a-note-on-performance)
@@ -91,7 +92,7 @@
 ```
 
 
-## Running `doctest` for a Cabal package
+# Running `doctest` for a Cabal package
 
 The easiest way to run `doctest` for a Cabal package is via `cabal repl --with-ghc=doctest`.
 
@@ -134,6 +135,7 @@
 - `doctest` always uses the version of GHC it was compiled with.  Reinstalling
   `doctest` with `cabal install doctest --overwrite-policy=always` before each
   invocation ensures that it uses the same version of GHC as is on the `PATH`.
+
 - Technically, `cabal build` is not necessary. `cabal repl --with-ghc=doctest`
   will build any dependencies as needed.  However, it's more robust to run
   `cabal build` first (specifically it is not a good idea to build
@@ -147,7 +149,29 @@
 
 (This is what you want to use on CI.)
 
+## Passing `doctest` options to `cabal repl`
 
+You can pass `doctest` options like `--fast`, `--preserve-it` and `--verbose` to
+`cabal repl` via `--repl-options`.
+
+Example:
+
+```
+$ cabal repl --with-ghc=doctest --repl-options=--verbose
+### Started execution at src/Fib.hs:7.
+### example:
+fib 10
+### Successful!
+
+### Started execution at src/Fib.hs:10.
+### example:
+fib 5
+### Successful!
+
+# Final summary:
+Examples: 2  Tried: 2  Errors: 0  Failures: 0
+```
+
 # Writing examples and properties
 
 ## Example groups
@@ -185,7 +209,7 @@
 (With the caveat that the order in which groups appear now matters!)
 
 However, note that due to a
-[bug on GHC 8.2.1 or later](https://ghc.haskell.org/trac/ghc/ticket/14052),
+[bug on GHC 8.2.1 or later](https://gitlab.haskell.org/ghc/ghc/-/issues/14052),
 the performance of `--fast` suffers significantly when combined with the
 `--preserve-it` flag (which keeps the value of GHCi's `it` value between
 examples).
diff --git a/doctest.cabal b/doctest.cabal
--- a/doctest.cabal
+++ b/doctest.cabal
@@ -1,11 +1,11 @@
 cabal-version: 1.12
 
--- This file has been generated from package.yaml by hpack version 0.35.0.
+-- This file has been generated from package.yaml by hpack version 0.35.1.
 --
 -- see: https://github.com/sol/hpack
 
 name:           doctest
-version:        0.20.1
+version:        0.21.0
 synopsis:       Test interactive Haskell examples
 description:    `doctest` is a tool that checks [examples](https://www.haskell.org/haddock/doc/html/ch03s08.html#idm140354810775744)
                 and [properties](https://www.haskell.org/haddock/doc/html/ch03s08.html#idm140354810771856)
diff --git a/ghci-wrapper/src/Language/Haskell/GhciWrapper.hs b/ghci-wrapper/src/Language/Haskell/GhciWrapper.hs
--- a/ghci-wrapper/src/Language/Haskell/GhciWrapper.hs
+++ b/ghci-wrapper/src/Language/Haskell/GhciWrapper.hs
@@ -43,14 +43,18 @@
 itMarker = "d42472243a0e6fc481e7514cbc9eb08812ed48daa29ca815844d86010b1d113a"
 
 data Interpreter = Interpreter {
-    hIn  :: Handle
-  , hOut :: Handle
-  , process :: ProcessHandle
-  }
+  hIn  :: Handle
+, hOut :: Handle
+, process :: ProcessHandle
+}
 
 new :: Config -> [String] -> IO Interpreter
 new Config{..} args_ = do
-  (Just stdin_, Just stdout_, Nothing, processHandle ) <- createProcess $ (proc configGhci args) {std_in = CreatePipe, std_out = CreatePipe, std_err = Inherit}
+  (Just stdin_, Just stdout_, Nothing, processHandle ) <- createProcess (proc configGhci args) {
+    std_in  = CreatePipe
+  , std_out = CreatePipe
+  , std_err = Inherit
+  }
   setMode stdin_
   setMode stdout_
   let interpreter = Interpreter {hIn = stdin_, hOut = stdout_, process = processHandle}
@@ -134,7 +138,7 @@
     echo :: String -> IO ()
     echo
       | echoMode = putStr
-      | otherwise = (const $ return ())
+      | otherwise = \ _ -> return ()
 
 -- | Evaluate an expression
 eval :: Interpreter -> String -> IO String
diff --git a/src/Options.hs b/src/Options.hs
--- a/src/Options.hs
+++ b/src/Options.hs
@@ -3,12 +3,9 @@
 module Options (
   Result(..)
 , Run(..)
-, defaultMagic
-, defaultFastMode
-, defaultPreserveIt
-, defaultVerbose
 , parseOptions
 #ifdef TEST
+, defaultRun
 , usage
 , info
 , versionInfo
@@ -72,26 +69,14 @@
   , "--abi-hash"
   ]
 
-defaultMagic :: Bool
-defaultMagic = True
-
-defaultFastMode :: Bool
-defaultFastMode = False
-
-defaultPreserveIt :: Bool
-defaultPreserveIt = False
-
-defaultVerbose :: Bool
-defaultVerbose = False
-
 defaultRun :: Run
 defaultRun = Run {
   runWarnings = []
 , runOptions = []
-, runMagicMode = defaultMagic
-, runFastMode = defaultFastMode
-, runPreserveIt = defaultPreserveIt
-, runVerbose = defaultVerbose
+, runMagicMode = False
+, runFastMode = False
+, runPreserveIt = False
+, runVerbose = False
 }
 
 modifyWarnings :: ([String] -> [String]) -> Run -> Run
@@ -114,51 +99,41 @@
 
 parseOptions :: [String] -> Result Run
 parseOptions args
-  | "--info" `elem` args = Output info
-  | "--interactive" `elem` args = Result Run {
-        runWarnings = []
-      , runOptions = filter (/= "--interactive") args
-      , runMagicMode = False
-      , runFastMode = False
-      , runPreserveIt = False
-      , runVerbose = False
-      }
-  | any (`elem` nonInteractiveGhcOptions) args = RunGhc args
-  | "--help" `elem` args = Output usage
-  | "--version" `elem` args = Output versionInfo
-  | otherwise = case execRWS parse () args of
-      (xs, Endo setter) ->
-        Result (setOptions xs $ setter defaultRun)
-    where
-      parse :: RWS () (Endo Run) [String] ()
-      parse = do
-        stripNoMagic
-        stripFast
-        stripPreserveIt
-        stripVerbose
-        stripOptGhc
-
-stripNoMagic :: RWS () (Endo Run) [String] ()
-stripNoMagic = stripFlag (setMagicMode False) "--no-magic"
+  | on "--info" = Output info
+  | on "--interactive" = runRunOptionsParser (discard "--interactive" args) defaultRun $ do
+      commonRunOptions
+  | on `any` nonInteractiveGhcOptions = RunGhc args
+  | on "--help" = Output usage
+  | on "--version" = Output versionInfo
+  | otherwise = runRunOptionsParser args defaultRun {runMagicMode = True} $ do
+      commonRunOptions
+      parseFlag "--no-magic" (setMagicMode False)
+      parseOptGhc
+  where
+    on option = option `elem` args
 
-stripFast :: RWS () (Endo Run) [String] ()
-stripFast = stripFlag (setFastMode True) "--fast"
+type RunOptionsParser = RWS () (Endo Run) [String] ()
 
-stripPreserveIt :: RWS () (Endo Run) [String] ()
-stripPreserveIt = stripFlag (setPreserveIt True) "--preserve-it"
+runRunOptionsParser :: [String] -> Run -> RunOptionsParser -> Result Run
+runRunOptionsParser args def parse = case execRWS parse () args of
+  (xs, Endo setter) ->
+    Result (setOptions xs $ setter def)
 
-stripVerbose :: RWS () (Endo Run) [String] ()
-stripVerbose = stripFlag (setVerbose True) "--verbose"
+commonRunOptions :: RunOptionsParser
+commonRunOptions = do
+  parseFlag "--fast" (setFastMode True)
+  parseFlag "--preserve-it" (setPreserveIt True)
+  parseFlag "--verbose" (setVerbose True)
 
-stripFlag :: (Run -> Run) -> String -> RWS () (Endo Run) [String] ()
-stripFlag setter flag = do
+parseFlag :: String -> (Run -> Run) -> RunOptionsParser
+parseFlag flag setter = do
   args <- RWS.get
   when (flag `elem` args) $
     RWS.tell (Endo setter)
-  RWS.put (filter (/= flag) args)
+  RWS.put (discard flag args)
 
-stripOptGhc :: RWS () (Endo Run) [String] ()
-stripOptGhc = do
+parseOptGhc :: RunOptionsParser
+parseOptGhc = do
   issueWarning <- RWS.state go
   when issueWarning $
     RWS.tell $ Endo $ modifyWarnings (++ [warning])
@@ -169,3 +144,6 @@
       opt : rest -> maybe (fmap (opt :)) (\x (_, xs) -> (True, x : xs)) (stripPrefix "--optghc=" opt) (go rest)
 
     warning = "WARNING: --optghc is deprecated, doctest now accepts arbitrary GHC options\ndirectly."
+
+discard :: String -> [String] -> [String]
+discard flag = filter (/= flag)
diff --git a/src/Runner.hs b/src/Runner.hs
--- a/src/Runner.hs
+++ b/src/Runner.hs
@@ -129,7 +129,7 @@
     reload = do
       unless fastMode $
         -- NOTE: It is important to do the :reload first! See
-        -- https://ghc.haskell.org/trac/ghc/ticket/5904, which results in a
+        -- https://gitlab.haskell.org/ghc/ghc/-/issues/5904, which results in a
         -- panic on GHC 7.4.1 if you do the :reload second.
         void $ Interpreter.safeEval repl ":reload"
       void $ Interpreter.safeEval repl $ ":m *" ++ module_
diff --git a/test/MainSpec.hs b/test/MainSpec.hs
--- a/test/MainSpec.hs
+++ b/test/MainSpec.hs
@@ -8,7 +8,6 @@
 import           Control.Exception
 import           System.Directory (getCurrentDirectory, setCurrentDirectory)
 import           System.FilePath
-import           Options
 import           Runner (Summary(..))
 import           Run hiding (doctest)
 import           System.IO.Silently
@@ -22,11 +21,11 @@
 
 -- | Construct a doctest specific 'Assertion'.
 doctest :: HasCallStack => FilePath -> [String] -> Summary -> Assertion
-doctest = doctestWithPreserveIt defaultPreserveIt
+doctest = doctestWithPreserveIt False
 
 doctestWithPreserveIt :: HasCallStack => Bool -> FilePath -> [String] -> Summary -> Assertion
 doctestWithPreserveIt preserveIt workingDir args expected = do
-  actual <- withCurrentDirectory ("test/integration" </> workingDir) (hSilence [stderr] $ doctestWithOptions defaultFastMode preserveIt defaultVerbose args)
+  actual <- withCurrentDirectory ("test/integration" </> workingDir) (hSilence [stderr] $ doctestWithOptions False preserveIt False args)
   assertEqual label expected actual
   where
     label = workingDir ++ " " ++ show args
diff --git a/test/OptionsSpec.hs b/test/OptionsSpec.hs
--- a/test/OptionsSpec.hs
+++ b/test/OptionsSpec.hs
@@ -18,12 +18,19 @@
 spec :: Spec
 spec = do
   describe "parseOptions" $ do
-    let warning = ["WARNING: --optghc is deprecated, doctest now accepts arbitrary GHC options\ndirectly."]
+    let
+      run :: [String] -> Run
+      run options = defaultRun {
+        runWarnings = ["WARNING: --optghc is deprecated, doctest now accepts arbitrary GHC options\ndirectly."]
+      , runOptions = options
+      , runMagicMode = True
+      }
+
     it "strips --optghc" $
-      parseOptions ["--optghc", "foobar"] `shouldBe` Result (Run warning ["foobar"] defaultMagic defaultFastMode defaultPreserveIt defaultVerbose)
+      parseOptions ["--optghc", "foobar"] `shouldBe` Result (run ["foobar"])
 
     it "strips --optghc=" $
-      parseOptions ["--optghc=foobar"] `shouldBe` Result (Run warning ["foobar"] defaultMagic defaultFastMode defaultPreserveIt defaultVerbose)
+      parseOptions ["--optghc=foobar"] `shouldBe` Result (run ["foobar"])
 
     context "with ghc options that are not valid with --interactive" $ do
       it "returns RunGhc" $ do
@@ -39,6 +46,9 @@
 
       it "filters out --interactive" $ do
         runOptions <$> parseOptions options `shouldBe` Result ["--foo", "--bar"]
+
+      it "accepts --fast" $ do
+        runFastMode <$> parseOptions ("--fast" : options) `shouldBe` Result True
 
     describe "--no-magic" $ do
       context "without --no-magic" $ do
diff --git a/test/RunSpec.hs b/test/RunSpec.hs
--- a/test/RunSpec.hs
+++ b/test/RunSpec.hs
@@ -20,7 +20,7 @@
 import           Run
 
 doctestWithDefaultOptions :: [String] -> IO Summary
-doctestWithDefaultOptions = doctestWithOptions Options.defaultFastMode Options.defaultPreserveIt Options.defaultVerbose
+doctestWithDefaultOptions = doctestWithOptions False False False
 
 withCurrentDirectory :: FilePath -> IO a -> IO a
 withCurrentDirectory workingDir action = do
