diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,10 @@
 # Revision history for array-builder
 
+## 0.1.1.0 -- 2020-11-18
+
+* Add `new1`.
+* Add `Data.Builder.(doubleton|tripleton)`.
+
 ## 0.1.0.0 -- 2019-09-12
 
-* First version. Released on an unsuspecting world.
+* First version.
diff --git a/array-builder.cabal b/array-builder.cabal
--- a/array-builder.cabal
+++ b/array-builder.cabal
@@ -1,6 +1,6 @@
 cabal-version: 2.2
 name: array-builder
-version: 0.1.0.0
+version: 0.1.1.0
 synopsis: Builders for arrays
 homepage: https://github.com/andrewthad/array-builder
 bug-reports: https://github.com/andrewthad/array-builder/issues
@@ -16,12 +16,18 @@
   exposed-modules:
     Data.Builder
     Data.Builder.ST
+  other-modules:
+    Compat
   build-depends:
+    , array-chunks >=0.1 && <0.2
     , base >=4.12 && <5
     , primitive >=0.6.4 && <0.8
     , run-st >=0.1 && <0.2
-    , array-chunks >=0.1 && <0.2
   hs-source-dirs: src
+  if impl(ghc >= 8.9)
+    hs-source-dirs: src-post-8.9
+  else
+    hs-source-dirs: src-pre-8.9
   default-language: Haskell2010
   ghc-options: -Wall -O2
 
@@ -30,8 +36,8 @@
   hs-source-dirs: test
   main-is: Main.hs
   build-depends:
-    , base
     , array-builder
+    , base
     , tasty
     , tasty-hunit
   ghc-options: -Wall -O2
diff --git a/src-post-8.9/Compat.hs b/src-post-8.9/Compat.hs
new file mode 100644
--- /dev/null
+++ b/src-post-8.9/Compat.hs
@@ -0,0 +1,38 @@
+{-# language MagicHash #-}
+{-# language UnboxedTuples #-}
+
+module Compat
+  ( unsafeShrinkAndFreeze
+  , unsafeShrinkAndFreeze#
+  ) where
+
+import Data.Primitive (SmallArray(..),SmallMutableArray(..))
+import GHC.Exts (SmallArray#,SmallMutableArray#,Int(I#))
+import GHC.Exts (State#,Int#)
+import GHC.ST (ST(ST))
+
+import qualified GHC.Exts as Exts
+
+-- Shrink the mutable array in place and then freeze it.
+-- The argument must not be reused after being passed to
+-- this function.
+unsafeShrinkAndFreeze ::
+     SmallMutableArray s a
+  -> Int
+  -> ST s (SmallArray a)
+{-# inline unsafeShrinkAndFreeze #-}
+unsafeShrinkAndFreeze (SmallMutableArray x) (I# n) = ST
+  (\s0 -> case Exts.shrinkSmallMutableArray# x n s0 of
+    s1 -> case Exts.unsafeFreezeSmallArray# x s1 of
+      (# s2, r #) -> (# s2, SmallArray r #)
+  )
+
+unsafeShrinkAndFreeze# ::
+     SmallMutableArray# s a
+  -> Int#
+  -> State# s
+  -> (# State# s, SmallArray# a #)
+{-# inline unsafeShrinkAndFreeze# #-}
+unsafeShrinkAndFreeze# x n s0 =
+  case Exts.shrinkSmallMutableArray# x n s0 of
+    s1 -> Exts.unsafeFreezeSmallArray# x s1
diff --git a/src-pre-8.9/Compat.hs b/src-pre-8.9/Compat.hs
new file mode 100644
--- /dev/null
+++ b/src-pre-8.9/Compat.hs
@@ -0,0 +1,33 @@
+{-# language MagicHash #-}
+{-# language UnboxedTuples #-}
+
+module Compat
+  ( unsafeShrinkAndFreeze
+  , unsafeShrinkAndFreeze#
+  ) where
+
+import Control.Monad.ST (ST)
+import Data.Primitive (SmallArray,SmallMutableArray)
+import GHC.Exts (SmallArray#,SmallMutableArray#,Int#,State#)
+
+import qualified Data.Primitive as PM
+import qualified GHC.Exts as Exts
+
+-- Shrink the mutable array in place and then freeze it.
+-- The argument must not be reused after being passed to
+-- this function.
+unsafeShrinkAndFreeze ::
+     SmallMutableArray s a
+  -> Int
+  -> ST s (SmallArray a)
+{-# inline unsafeShrinkAndFreeze #-}
+unsafeShrinkAndFreeze arr = PM.freezeSmallArray arr 0
+
+unsafeShrinkAndFreeze# ::
+     SmallMutableArray# s a
+  -> Int#
+  -> State# s
+  -> (# State# s, SmallArray# a #)
+{-# inline unsafeShrinkAndFreeze# #-}
+unsafeShrinkAndFreeze# x n s0 =
+  Exts.freezeSmallArray# x 0# n s0
diff --git a/src/Data/Builder.hs b/src/Data/Builder.hs
--- a/src/Data/Builder.hs
+++ b/src/Data/Builder.hs
@@ -8,22 +8,22 @@
     Builder(..)
   , cons
   , singleton
+  , doubleton
+  , tripleton
     -- * Run
   , run
   ) where
 
+import Compat (unsafeShrinkAndFreeze#)
+import Data.Chunks (Chunks(ChunksNil,ChunksCons))
 import Data.Primitive (SmallArray(SmallArray))
-import Control.Monad.ST.Run (runSmallArrayST)
+import GHC.Exts ((*#),(+#),(-#),(>#))
+import GHC.Exts (SmallMutableArray#)
 import GHC.Exts (State#,Int#,runRW#)
+import GHC.Exts (newSmallArray#)
 import GHC.Exts (writeSmallArray#,unsafeFreezeSmallArray#)
-import GHC.Exts (SmallMutableArray#,freezeSmallArray#)
-import GHC.Exts (newSmallArray#,sizeofSmallArray#)
-import GHC.Exts ((*#),(+#),(-#),(>#))
-import Data.Chunks (Chunks(ChunksNil,ChunksCons))
 
 import qualified Data.Chunks as C
-import qualified Data.Foldable as F
-import qualified Data.Primitive as PM
 
 -- | Builder for an array of boxed elements.
 newtype Builder a = Builder
@@ -45,7 +45,7 @@
         -- Recall that freezeSmallArray copies a slice.
         -- If resize functions ever become available for
         -- SmallArray, we should use that instead.
-        case freezeSmallArray# marr 0# off s2 of
+        case unsafeShrinkAndFreeze# marr off s2 of
           (# s3, arr #) ->
             let !r = C.reverseOnto
                   (ChunksCons (SmallArray arr) ChunksNil)
@@ -76,6 +76,7 @@
 {-# inline cons #-}
 cons a b = singleton a <> b
 
+-- | A builder with one element.
 singleton :: a -> Builder a
 {-# noinline singleton #-}
 singleton a = Builder
@@ -83,13 +84,55 @@
     1# -> case writeSmallArray# marr off a s0 of
       s1 -> (# s1, marr, off +# 1#, len -# 1#, cs #)
     _ -> case unsafeFreezeSmallArray# marr s0 of
-      (# s1, arr #) -> let !lenNew = nextLength (sizeofSmallArray# arr) in
+      (# s1, arr #) -> let !lenNew = nextLength off in
         -- Since we feed the element to newSmallArray#, we do not
         -- need to write it to the 0 index.
         case newSmallArray# lenNew a s1 of
           (# s2, marrNew #) ->
             let !csNew = ChunksCons (SmallArray arr) cs in
               (# s2, marrNew, 1#, lenNew -# 1#, csNew #)
+  )
+
+-- | A builder with two elements.
+--
+-- @since 0.1.1.0
+doubleton :: a -> a -> Builder a
+{-# noinline doubleton #-}
+doubleton a b = Builder
+  (\marr off len cs s0 -> case len ># 1# of
+    1# -> case writeSmallArray# marr off a s0 of
+      s1 -> case writeSmallArray# marr (off +# 1#) b s1 of
+        s2 -> (# s2, marr, off +# 2#, len -# 2#, cs #)
+    _ -> case unsafeShrinkAndFreeze# marr off s0 of
+      (# s1, arr #) -> let !lenNew = nextLength off in
+        -- Since we feed the element to newSmallArray#, we do not
+        -- need to write element a to the 0 index.
+        case newSmallArray# lenNew a s1 of
+          (# s2, marrNew #) -> case writeSmallArray# marrNew 1# b s2 of
+            s3 -> let !csNew = ChunksCons (SmallArray arr) cs in
+              (# s3, marrNew, 2#, lenNew -# 2#, csNew #)
+  )
+
+-- | A builder with three elements.
+--
+-- @since 0.1.1.0
+tripleton :: a -> a -> a -> Builder a
+{-# noinline tripleton #-}
+tripleton a b c = Builder
+  (\marr off len cs s0 -> case len ># 1# of
+    1# -> case writeSmallArray# marr off a s0 of
+      s1 -> case writeSmallArray# marr (off +# 1#) b s1 of
+        s2 -> case writeSmallArray# marr (off +# 2#) c s2 of
+          s3 -> (# s3, marr, off +# 3#, len -# 3#, cs #)
+    _ -> case unsafeShrinkAndFreeze# marr off s0 of
+      (# s1, arr #) -> let !lenNew = nextLength off in
+        -- Since we feed the element to newSmallArray#, we do not
+        -- need to write element a to the 0 index.
+        case newSmallArray# lenNew a s1 of
+          (# s2, marrNew #) -> case writeSmallArray# marrNew 1# b s2 of
+            s3 -> case writeSmallArray# marrNew 2# c s3 of
+              s4 -> let !csNew = ChunksCons (SmallArray arr) cs in
+                (# s4, marrNew, 3#, lenNew -# 3#, csNew #)
   )
 
 nextLength :: Int# -> Int#
diff --git a/src/Data/Builder/ST.hs b/src/Data/Builder/ST.hs
--- a/src/Data/Builder/ST.hs
+++ b/src/Data/Builder/ST.hs
@@ -3,15 +3,17 @@
 module Data.Builder.ST
   ( Builder(..)
   , new
+  , new1
   , push
   , freeze 
   ) where
 
-import Data.Primitive (SmallMutableArray)
+import Compat (unsafeShrinkAndFreeze)
 import Control.Monad.ST (ST)
-import Data.Primitive (newSmallArray,writeSmallArray,unsafeFreezeSmallArray)
-import Data.Primitive (sizeofSmallArray,freezeSmallArray)
 import Data.Chunks (Chunks(ChunksNil,ChunksCons))
+import Data.Primitive (SmallMutableArray)
+import Data.Primitive (newSmallArray,writeSmallArray,unsafeFreezeSmallArray)
+import Data.Primitive (sizeofSmallArray)
 import Foreign.Storable (sizeOf)
 
 import qualified Data.Chunks as C
@@ -35,6 +37,17 @@
   marr <- newSmallArray initialLength errorThunk
   pure (Builder marr 0 initialLength ChunksNil)
 
+-- | Create a new 'Builder' with a single element. Useful when builder
+-- creation is immidiately followed by 'push'. Note that:
+--
+-- > new >>= push x ≡ new1 x
+--
+-- But 'new1' performs slightly better.
+new1 :: a -> ST s (Builder s a)
+new1 a0 = do
+  marr <- newSmallArray initialLength a0
+  pure (Builder marr 1 initialLength ChunksNil)
+
 -- | Push an element onto the end of the builder. This
 -- is not strict in the element, so force it before pushing
 -- it on to the builder if doing so is needed to prevent
@@ -55,8 +68,8 @@
     pure $! Builder marrNew 1 (lenNew - 1) csNew
 
 -- The sequence of sizes we create is:
---   64-bit: 14, 30, 62, 126, 254, 254, 254...
---   32-bit: 14, 30, 62, 126, 254, 510, 510, 510...
+--   64-bit: 6, 14, 30, 62, 126, 254, 254, 254...
+--   32-bit: 6, 14, 30, 62, 126, 254, 510, 510, 510...
 -- The goal is to have objects whose sizes are increasing
 -- powers of 2 until we reach the size of a block (4KB).
 -- A 254-element SmallArray on a 64-bit platform uses
@@ -81,7 +94,7 @@
      Builder s a -- ^ Builder, do not reuse after freezing
   -> ST s (Chunks a)
 freeze (Builder marr off _ cs) = do
-  arr <- freezeSmallArray marr 0 off
+  arr <- unsafeShrinkAndFreeze marr off
   pure $! C.reverseOnto (ChunksCons arr ChunksNil) cs
 
 errorThunk :: a
diff --git a/test/Main.hs b/test/Main.hs
--- a/test/Main.hs
+++ b/test/Main.hs
@@ -2,14 +2,12 @@
 {-# language ScopedTypeVariables #-}
 {-# language TypeApplications #-}
 
-import Data.Builder (singleton,run)
-import Control.Monad.ST (runST)
+import Data.Builder (singleton,doubleton,tripleton,run)
 import Test.Tasty (defaultMain,testGroup,TestTree)
 import Test.Tasty.HUnit ((@=?))
 import Data.Semigroup (stimes)
 import qualified Data.List as L
 import qualified Data.Foldable as F
-import qualified GHC.Exts as Exts
 import qualified Test.Tasty.HUnit as THU
 
 main :: IO ()
@@ -37,4 +35,17 @@
     )
   , THU.testCase "C" $ (L.replicate 500 'X') @=?
     (F.toList $ run (stimes (500 :: Int) (singleton 'X')))
+  , THU.testCase "D" $ "ACDCDCDCDCDCDCDCDCDX" @=?
+    ( F.toList $ run
+      (  singleton 'A'
+      <> stimes (9 :: Int) (doubleton 'C' 'D')
+      <> singleton 'X'
+      )
+    )
+  , THU.testCase "E" $ "ABCABCABCABCABCABCABCX" @=?
+    ( F.toList $ run
+      (  stimes (7 :: Int) (tripleton 'A' 'B' 'C')
+      <> singleton 'X'
+      )
+    )
   ]
