diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 2.9.8.1
+
+* Improve performance by adding `INLINE` pragmas to `Monad` etc. combinators.
+
 ## 2.9.8
 
 * Add `integrity_`, `crossorigin_` attributes
diff --git a/benchmarks/IO.hs b/benchmarks/IO.hs
new file mode 100644
--- /dev/null
+++ b/benchmarks/IO.hs
@@ -0,0 +1,24 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Main where
+
+import Lucid
+import Criterion.Main
+import Control.Monad (replicateM_)
+import qualified Data.Text.Lazy as LT
+import Control.Monad.Trans.Reader (runReader)
+import Data.Functor.Identity (runIdentity)
+
+lotsOfDivs :: Monad m => Int -> HtmlT m ()
+lotsOfDivs n = body_
+  $ replicateM_ n
+  $ div_ "hello world!"
+
+main :: IO ()
+main = defaultMain
+    [ bench "renderText"            $ nf (renderText  . lotsOfDivs) size
+    , bench "renderTextT Identity"  $ nf (runIdentity . renderTextT . lotsOfDivs) size
+    , bench "renderTextT Reader"    $ nf (\(r, s) -> flip runReader r . renderTextT . lotsOfDivs $ s) ((), size)
+    , bench "renderTextT IO"        $ nfIO (renderTextT (lotsOfDivs size) :: IO LT.Text)
+    ]
+  where
+    size = 10000
diff --git a/lucid.cabal b/lucid.cabal
--- a/lucid.cabal
+++ b/lucid.cabal
@@ -1,5 +1,5 @@
 name:                lucid
-version:             2.9.8
+version:             2.9.8.1
 synopsis:            Clear to write, read and edit DSL for HTML
 description:         Clear to write, read and edit DSL for HTML. See the 'Lucid' module
                      for description and documentation.
@@ -60,5 +60,16 @@
                     blaze-builder,
                     text,
                     bytestring,
+                    lucid
+  ghc-options:      -O2
+
+benchmark bench-io
+  type:             exitcode-stdio-1.0
+  hs-source-dirs:   benchmarks
+  main-is:          IO.hs
+  build-depends:    base,
+                    criterion,
+                    transformers,
+                    text,
                     lucid
   ghc-options:      -O2
diff --git a/src/Lucid/Base.hs b/src/Lucid/Base.hs
--- a/src/Lucid/Base.hs
+++ b/src/Lucid/Base.hs
@@ -111,21 +111,48 @@
 
 -- | Based on the monad instance.
 instance Monad m => Applicative (HtmlT m) where
-  pure = return
-  (<*>) = ap
+  pure a = HtmlT (return (mempty,a))
+  {-# INLINE pure #-}
 
+  f <*> x = HtmlT $ do
+    ~(g, f') <- runHtmlT f
+    ~(h, x') <- runHtmlT x
+    return (g <> h, f' x')
+  {-# INLINE (<*>) #-}
+
+  m *> n = HtmlT $ do
+    ~(g, _) <- runHtmlT m
+    ~(h, b) <- runHtmlT n
+    return (g <> h, b)
+  {-# INLINE (*>) #-}
+
+  m <* n = HtmlT $ do
+    ~(g, a) <- runHtmlT m
+    ~(h, _) <- runHtmlT n
+    return (g <> h, a)
+  {-# INLINE (<*) #-}
+
 -- | Just re-uses Monad.
 instance Monad m => Functor (HtmlT m) where
   fmap = liftM
 
+  (<$) = fmap . const
+  {-# INLINE (<$) #-}
+
 -- | Basically acts like Writer.
 instance Monad m => Monad (HtmlT m) where
-  return a = HtmlT (return (mempty,a))
-  m >>= f =
-    HtmlT (do ~(g,a) <- runHtmlT m
-              ~(h,b) <- runHtmlT (f a)
-              return (g <> h,b))
+  return = pure
+  {-# INLINE return #-}
 
+  m >>= f = HtmlT $ do
+    ~(g,a) <- runHtmlT m
+    ~(h,b) <- runHtmlT (f a)
+    return (g <> h,b)
+  {-# INLINE (>>=) #-}
+
+  (>>) = (*>)
+  {-# INLINE (>>) #-}
+
 -- | Used for 'lift'.
 instance MonadTrans HtmlT where
   lift m =
@@ -221,6 +248,8 @@
        -> arg    -- ^ Either an attribute list or children.
        -> result -- ^ Result: either an element or an attribute.
   term = flip termWith []
+  {-# INLINE term #-}
+
   -- | Use this if you want to make an element which inserts some
   -- pre-prepared attributes into the element.
   termWith :: Text          -- ^ Name.
@@ -236,6 +265,7 @@
 -- attributes.
 instance (Monad m) => Term (HtmlT m a) (HtmlT m a) where
   termWith name f = with (makeElement name) f
+  {-# INLINE termWith #-}
 
 -- | Some terms (like 'Lucid.Html5.style_', 'Lucid.Html5.title_') can be used for
 -- attributes as well as elements.
@@ -413,6 +443,7 @@
             => Text       -- ^ Name.
             -> HtmlT m a  -- ^ Children HTML.
             -> HtmlT m a -- ^ A parent element.
+{-# INLINE[1] makeElement #-}
 makeElement name =
   \m' ->
     HtmlT (do ~(f,a) <- runHtmlT m'
