diff --git a/benchmarks/BigTable/Blaze.hs b/benchmarks/BigTable/Blaze.hs
--- a/benchmarks/BigTable/Blaze.hs
+++ b/benchmarks/BigTable/Blaze.hs
@@ -1,4 +1,5 @@
 {-# LANGUAGE OverloadedStrings #-}
+-- derived from https://github.com/jaspervdj/blaze-markup/blob/master/benchmarks/bigtable/html.hs
 module BigTable.Blaze where
 import           Criterion.Main                (Benchmark, bench, nf)
 import           Data.Text.Lazy                (Text)
@@ -34,9 +35,9 @@
   p "i am gref at lots of static data\n"
   p "i am greg at lots of static data\n"
   where
-    row r = tr (mapM_ (\t -> do
+    row r = tr (mapM_ (\t -> td $ do
                           p "hi!\n"
-                          td (toHtml t)
+                          toHtml t
                           p "hello!\n") r)
 
 benchmark :: [[Int]] -> Benchmark
diff --git a/benchmarks/BigTable/Lucid.hs b/benchmarks/BigTable/Lucid.hs
--- a/benchmarks/BigTable/Lucid.hs
+++ b/benchmarks/BigTable/Lucid.hs
@@ -1,4 +1,5 @@
 {-# LANGUAGE OverloadedStrings #-}
+-- derived from https://github.com/jaspervdj/blaze-markup/blob/master/benchmarks/bigtable/html.h
 module BigTable.Lucid where
 import           Criterion.Main (Benchmark, bench, nf)
 import           Data.Text.Lazy (Text)
@@ -39,9 +40,9 @@
 
   where
     row :: [Int] -> Html ()
-    row r = tr_ (mapM_ (\t -> do
+    row r = tr_ (mapM_ (\t -> td_ $ do
                           p_ "hi!\n"
-                          td_ (toHtml (show t))
+                          toHtml (show t)
                           p_ "hello!\n") r)
 
 benchmark :: [[Int]] -> Benchmark
diff --git a/benchmarks/BigTable/Nice.hs b/benchmarks/BigTable/Nice.hs
--- a/benchmarks/BigTable/Nice.hs
+++ b/benchmarks/BigTable/Nice.hs
@@ -1,9 +1,14 @@
 {-# LANGUAGE OverloadedStrings #-}
+-- derived from https://github.com/jaspervdj/blaze-markup/blob/master/benchmarks/bigtable/html.h
 module BigTable.Nice where
-import           Criterion.Main        (Benchmark, bench, nf)
-import           Data.Functor.Identity
+import           Control.Monad.Trans.Reader (runReader)
+import           Criterion.Main             (Benchmark, bench, nf)
+import           Data.Text.Lazy             (Text)
+import           Data.Text.Lazy.Builder     (Builder, toLazyText)
+import           Data.Text.Lazy.Builder.Int (decimal)
+import           Weigh                      (Weigh, func)
+
 import           Text.Html.Nice
-import           Weigh                 (Weigh, func)
 
 rows :: FastMarkup ([[Int]] -> FastMarkup (FastMarkup Builder))
 rows = compile $ do
@@ -34,8 +39,7 @@
   p_ "i am greg at lots of static data\n"
 
 bigTable :: [[Int]] -> Text
-bigTable table =
-  toLazyText (runIdentity (r (rows :$ table)))
+bigTable table = toLazyText (r rows `runReader` table)
 
 benchmark :: [[Int]] -> Benchmark
 benchmark t = bench "nice" (bigTable `nf` t)
diff --git a/benchmarks/Mem.hs b/benchmarks/Mem.hs
--- a/benchmarks/Mem.hs
+++ b/benchmarks/Mem.hs
@@ -12,7 +12,7 @@
 
 main :: IO ()
 main = do
-
+{-
   -- Sanity checks
   let
     check l f g =
@@ -31,6 +31,7 @@
   check "nice = blaze" Nice.bigTable Blaze.bigTable
   check "nice = lucid" Nice.bigTable Lucid.bigTable
   check "lucid = blaze" Lucid.bigTable Blaze.bigTable
+-}
 
   Mem.mainWith $ forM_ [10, 100, 1000] $ \i -> do
     let table = rows i
diff --git a/benchmarks/Perf.hs b/benchmarks/Perf.hs
--- a/benchmarks/Perf.hs
+++ b/benchmarks/Perf.hs
@@ -11,7 +11,7 @@
 
 main :: IO ()
 main = do
-
+{-
   -- Sanity checks
   let
     check l f g =
@@ -30,6 +30,7 @@
   check "nice = blaze" Nice.bigTable Blaze.bigTable
   check "nice = lucid" Nice.bigTable Lucid.bigTable
   check "lucid = blaze" Lucid.bigTable Blaze.bigTable
+-}
 
   Perf.defaultMain
     [ Perf.bgroup (show i)
diff --git a/nice-html.cabal b/nice-html.cabal
--- a/nice-html.cabal
+++ b/nice-html.cabal
@@ -1,5 +1,5 @@
 name:           nice-html
-version:        0.3.0
+version:        0.4.0
 category:       Web
 description: A fast and nice HTML templating library with distinct compilation/rendering phases.
 synopsis: A fast and nice HTML templating library with distinct compilation/rendering phases.
@@ -33,10 +33,12 @@
     , template-haskell >= 2.11
     , blaze-markup >= 0.5
     , recursion-schemes >= 5.0.1
+    , containers >= 0.5
     , transformers
     , free >= 4.5
     , bifunctors >= 5.1
     , data-default-class
+    , lens >= 4.15
   exposed-modules:
       Text.Html.Nice
       Text.Html.Nice.Internal
@@ -64,6 +66,7 @@
     , nice-html
     , weigh
     , pretty-show
+    , transformers
   other-modules:
       BigTable.Blaze
       BigTable.Lucid
@@ -87,6 +90,7 @@
     , nice-html
     , weigh
     , pretty-show
+    , transformers
   other-modules:
       BigTable.Nice
   default-language: Haskell2010
@@ -108,6 +112,7 @@
     , nice-html
     , weigh
     , pretty-show
+    , transformers
   other-modules:
       BigTable.Blaze
       BigTable.Lucid
diff --git a/src/Text/Html/Nice.hs b/src/Text/Html/Nice.hs
--- a/src/Text/Html/Nice.hs
+++ b/src/Text/Html/Nice.hs
@@ -8,6 +8,7 @@
     -- * Rendering
   , FastMarkup
   , Render (..)
+  , r_
   , (:$) (..)
   , renderM
   , renderMs
@@ -15,22 +16,9 @@
     -- * Utility
   , recompile
   , unlayer
-    -- * Re-exports of 'TLB.Builder' functions
-  , module Data.Text.Lazy.Builder
-  , module Data.Text.Lazy.Builder.Int
-  , module Data.Text.Lazy.Builder.RealFloat
-    -- * Re-exports of lazy 'Text' functions
-  , Text
-  , fromStrict
-  , toStrict
   ) where
-import           Data.Text.Lazy                   (Text, fromStrict, toStrict)
-import           Data.Text.Lazy.Builder
-import           Data.Text.Lazy.Builder.Int
-import           Data.Text.Lazy.Builder.RealFloat
-import           Text.Html.Nice.Internal          ((:$) (..), Attr (..),
-                                                   FastMarkup, Render (..),
-                                                   recompile, render, renderM,
-                                                   renderMs, unlayer)
+import           Text.Html.Nice.Internal     ((:$) (..), Attr (..), FastMarkup,
+                                              Render (..), r_, recompile, render,
+                                              renderM, renderMs, unlayer)
 import           Text.Html.Nice.Writer
 import           Text.Html.Nice.Writer.Html5
diff --git a/src/Text/Html/Nice/FreeMonad.hs b/src/Text/Html/Nice/FreeMonad.hs
--- a/src/Text/Html/Nice/FreeMonad.hs
+++ b/src/Text/Html/Nice/FreeMonad.hs
@@ -168,7 +168,7 @@
 -- @ 'attr' #x [a,b,c] = 'node' "x" [a,b,c] @
 --
 attr :: MakeNode n a -> [Attr n] -> Markup n a
-attr (N f) a = f a
+attr (N f) = f
 
 runMarkup :: Markup n a -> Markup' n
 runMarkup h = runF (unMarkup h) (const Empty) F.embed
@@ -229,7 +229,7 @@
 -- | Insert a sub-template.
 {-# INLINE embed #-}
 embed :: (t -> FastMarkup n) -> Markup (t -> FastMarkup n) a
-embed f = dynamic f
+embed = dynamic
 
 {-# INLINE stream #-}
 stream :: Foldable f
diff --git a/src/Text/Html/Nice/Internal.hs b/src/Text/Html/Nice/Internal.hs
--- a/src/Text/Html/Nice/Internal.hs
+++ b/src/Text/Html/Nice/Internal.hs
@@ -68,6 +68,7 @@
   | Stream (Stream a)
   | Text !IsEscaped !SomeText
   | Hole !IsEscaped a
+  | Precompiled !(FastMarkup a)
   | Empty
   deriving (Show, Eq, Functor, Foldable) {- , Traversable) -}
 
@@ -217,6 +218,7 @@
   Hole e v -> FHole e v
   Stream a -> FStream a
   Empty -> FEmpty
+  Precompiled fm -> fm
 
 -- | Look for an immediate string-like term and render that
 immediateRender :: FastMarkup a -> Maybe TLB.Builder
@@ -320,6 +322,10 @@
 render :: FastMarkup Void -> TLB.Builder
 render = runIdentity . renderM absurd
 
+{-# INLINE r_ #-}
+r_ :: Render a Identity => a -> TLB.Builder
+r_ = runIdentity . r
+
 class Render a m where
   r :: a -> m TLB.Builder
 
@@ -363,6 +369,9 @@
 
 class ToFastMarkup a where
   toFastMarkup :: a -> FastMarkup b
+
+instance ToFastMarkup (FastMarkup Void) where
+  toFastMarkup = vacuous
 
 instance ToFastMarkup Text where
   {-# INLINE toFastMarkup #-}
diff --git a/src/Text/Html/Nice/Writer.hs b/src/Text/Html/Nice/Writer.hs
--- a/src/Text/Html/Nice/Writer.hs
+++ b/src/Text/Html/Nice/Writer.hs
@@ -133,6 +133,7 @@
 --------------------------------------------------------------------------------
 -- Node types
 
+{-# INLINE using #-}
 using :: ToFastMarkup b => (a -> b) -> Markup (a -> FastMarkup r) ()
 using f = dynamic (toFastMarkup . f)
 
