diff --git a/src-imp/Int8.hs b/src-imp/Int8.hs
new file mode 100644
--- /dev/null
+++ b/src-imp/Int8.hs
@@ -0,0 +1,173 @@
+{-# language MagicHash #-}
+{-# language RankNTypes #-}
+{-# language TypeApplications #-}
+{-# language TypeFamilies #-}
+{-# language TypeInType #-}
+{-# language StandaloneKindSignatures #-}
+{-# language UnboxedTuples #-}
+
+module Int8
+  ( R
+  , A#
+  , M#
+  , empty#
+  , index#
+  , write#
+  , read#
+  , unsafeFreeze#
+  , initialized#
+  , set#
+  , unsafeShrinkFreeze#
+  , thaw#
+  , freeze#
+  , copy#
+    -- Comparison
+  , lt
+  , gt
+  , eq
+  , lt#
+  , gt#
+  , eq#
+  , max
+    -- Metadata
+  , size
+  ) where
+
+import Prelude hiding (max)
+
+import GHC.Exts
+import Data.Kind (Type)
+import Data.Unlifted (PrimArray#(..),MutablePrimArray#(..))
+import EmptyPrimArray (emptyPrimArray#)
+
+import qualified GHC.Exts as Exts
+
+type A# = PrimArray# @'Int8Rep
+type M# = MutablePrimArray# @'Int8Rep
+type R = 'Int8Rep
+
+unsafeFromI8 :: forall (a :: TYPE 'Int8Rep). Int8# -> a
+unsafeFromI8 x = unsafeCoerce# x
+
+unsafeToI8 :: forall (a :: TYPE 'Int8Rep). a -> Int8#
+unsafeToI8 x = unsafeCoerce# x
+
+index# :: forall (a :: TYPE R). A# a -> Int# -> a
+index# (PrimArray# a) i = unsafeFromI8 (indexInt8Array# a i)
+
+write# :: forall (s :: Type) (a :: TYPE R).
+  M# s a -> Int# -> a -> State# s -> State# s
+write# (MutablePrimArray# m) ix a s = writeInt8Array# m ix (unsafeToI8 a) s
+
+read# :: forall (s :: Type) (a :: TYPE R).
+  M# s a -> Int# -> State# s -> (# State# s, a #)
+read# (MutablePrimArray# m) ix s = case readInt8Array# m ix s of
+  (# s', r #) -> case unsafeFromI8 r of
+    r' -> (# s', r' #)
+
+unsafeFreeze# :: forall (s :: Type) (a :: TYPE R).
+     M# s a
+  -> State# s
+  -> (# State# s, A# a #)
+unsafeFreeze# (MutablePrimArray# m) s0 = case unsafeFreezeByteArray# m s0 of
+  (# s1, v #) -> (# s1, PrimArray# v #)
+
+empty# :: forall (a :: TYPE R). (# #) -> A# a
+empty# = emptyPrimArray#
+
+initialized# :: forall (s :: Type) (a :: TYPE R).
+     Int#
+  -> a
+  -> State# s
+  -> (# State# s, M# s a #)
+initialized# n a s0 = case newByteArray# n s0 of
+  (# s1, m #) -> case Exts.setByteArray# m 0# n (Exts.int8ToInt# (unsafeToI8 a)) s1 of
+    s2 -> (# s2, MutablePrimArray# m #)
+
+set# :: forall (s :: Type) (a :: TYPE R).
+     M# s a
+  -> Int#
+  -> Int#
+  -> a
+  -> State# s
+  -> State# s
+set# (MutablePrimArray# m) off0 len0 a s0 = Exts.setByteArray# m off0 len0 (Exts.int8ToInt# (unsafeToI8 a)) s0
+
+-- shrink and freeze, all at once
+unsafeShrinkFreeze# ::
+     M# s a
+  -> Int#
+  -> State# s
+  -> (# State# s, A# a #)
+unsafeShrinkFreeze# (MutablePrimArray# m) i s0Alpha = case getSizeofMutableByteArray# m s0Alpha of
+  (# s0, sz #) -> case sz ==# i of
+    1# -> case Exts.unsafeFreezeByteArray# m s0 of
+      (# s1, v #) -> (# s1, PrimArray# v #)
+    _ -> case Exts.shrinkMutableByteArray# m i s0 of
+      s1 -> case Exts.unsafeFreezeByteArray# m s1 of
+        (# s2, v #) -> (# s2, PrimArray# v #)
+
+thaw# :: forall (s :: Type) (a :: TYPE R).
+     A# a
+  -> Int#
+  -> Int#
+  -> State# s
+  -> (# State# s, M# s a #)
+thaw# (PrimArray# v) off len s0 = case Exts.newByteArray# len s0 of
+  (# s1, m #) -> case Exts.copyByteArray# v off m 0# len s1 of
+    s2 -> (# s2, MutablePrimArray# m #)
+
+freeze# :: forall (s :: Type) (a :: TYPE R).
+     M# s a
+  -> Int#
+  -> Int#
+  -> State# s
+  -> (# State# s, A# a #)
+freeze# (MutablePrimArray# v) off len s0 = case Exts.newByteArray# len s0 of
+  (# s1, m #) -> case Exts.copyMutableByteArray# v off m 0# len s1 of
+    s2 -> case Exts.unsafeFreezeByteArray# m s2 of
+      (# s3, x #) -> (# s3, PrimArray# x #)
+
+copy# :: forall (s :: Type) (a :: TYPE R).
+     M# s a
+  -> Int#
+  -> A# a
+  -> Int#
+  -> Int#
+  -> State# s
+  -> State# s
+copy# (MutablePrimArray# m) doff (PrimArray# v) soff len s0 =
+  Exts.copyByteArray# v soff m doff len s0
+
+max :: forall (a :: TYPE R). a -> a -> a
+{-# inline max #-}
+max x y = if gt x y then x else y
+
+lt :: forall (a :: TYPE R). a -> a -> Bool
+{-# inline lt #-}
+lt x y = isTrue# (ltInt8# (unsafeToI8 x) (unsafeToI8 y))
+
+gt :: forall (a :: TYPE R). a -> a -> Bool
+{-# inline gt #-}
+gt x y = isTrue# (gtInt8# (unsafeToI8 x) (unsafeToI8 y))
+
+eq :: forall (a :: TYPE R). a -> a -> Bool
+{-# inline eq #-}
+eq x y = isTrue# (eqInt8# (unsafeToI8 x) (unsafeToI8 y))
+
+lt# :: forall (a :: TYPE R). a -> a -> Int#
+{-# inline lt# #-}
+lt# x y = ltInt8# (unsafeToI8 x) (unsafeToI8 y)
+
+gt# :: forall (a :: TYPE R). a -> a -> Int#
+{-# inline gt# #-}
+gt# x y = gtInt8# (unsafeToI8 x) (unsafeToI8 y)
+
+eq# :: forall (a :: TYPE R). a -> a -> Int#
+{-# inline eq# #-}
+eq# x y = eqInt8# (unsafeToI8 x) (unsafeToI8 y)
+
+size :: Int
+{-# inline size #-}
+size = 1
+
diff --git a/src/Vector/Int8.hs b/src/Vector/Int8.hs
new file mode 100644
--- /dev/null
+++ b/src/Vector/Int8.hs
@@ -0,0 +1,110 @@
+{-# language DataKinds #-}
+{-# language MagicHash #-}
+{-# language NumericUnderscores #-}
+{-# language BangPatterns #-}
+{-# language TypeApplications #-}
+{-# language TypeOperators #-}
+
+module Vector.Int8
+  ( -- Types
+    Vector(..)
+  , Vector#
+  , MutableVector(..)
+  , MutableVector#
+  , Bounded(..)
+  , Vector_(..)
+    -- * Primitives
+  , write#
+  , write
+  , read#
+  , index#
+  , index
+  , unlift
+  , substitute
+  , initialized
+  , unsafeCoerceLength
+  , expose
+  , expose#
+    -- * Ranges
+  , set
+  , setSlice
+    -- * Freeze
+  , unsafeShrinkFreeze
+  , unsafeFreeze
+  , freeze
+  , freezeSlice
+    -- * Copy
+  , thaw
+    -- * Composite
+  , any
+  , all
+  , map
+  , ifoldl'
+  , ifoldlSlice'
+  , replicate
+  , construct1
+  , construct3
+  , construct4
+  , construct5
+  , construct6
+  , construct7
+  , append
+  , clone
+  , cloneSlice
+    -- * Index
+  , index0
+  , index1
+  , index2
+  , index3
+  , index4
+  , index5
+  , index6
+  , index7
+  , index8
+    -- * Ordered
+  , unique
+  , equals
+  , elem
+  , findIndexEq
+  , maximum
+  , maximumSlice
+  , maximumSliceInitial
+  , bubbleSort
+  , bubbleSortSlice
+  , bubbleSortSliceInPlace
+  , mapEq
+    -- * Hide Length
+  , vector_
+    -- * Show
+  , show
+    -- * Interop with primitive
+  , cloneFromByteArray
+  ) where
+
+import Prelude hiding (replicate,map,maximum,Bounded,all,any,elem,show)
+
+import Arithmetic.Types (Nat#)
+import Data.Primitive (ByteArray)
+import GHC.Exts (Int8#)
+import GHC.Int (Int8(I8#))
+
+import Vector.Std.Int8
+import Vector.Ord.Int8
+import Vector.Eq.Int8
+
+import qualified Vector.Prim.Int8
+
+-- | Crashes the program if the range is out of bounds. That is,
+-- behavior is always well defined.
+--
+-- Interprets the bytes in a native-endian fashion.
+cloneFromByteArray ::
+     Int    -- ^ Offset into byte array, units are elements, not bytes
+  -> Nat# n -- ^ Length of the vector, units are elements, not bytes
+  -> ByteArray
+  -> Vector n Int8#
+cloneFromByteArray = Vector.Prim.Int8.unsafeCloneFromByteArray
+
+show :: Nat# n -> Vector n Int8# -> String
+show n v = liftShows (\i s -> shows (I8# i) s) n v ""
+
diff --git a/vext.cabal b/vext.cabal
--- a/vext.cabal
+++ b/vext.cabal
@@ -1,6 +1,6 @@
 cabal-version: 3.4
 name: vext
-version: 0.1.4.0
+version: 0.1.5.0
 synopsis: Array library monomorphized with backpack
 bug-reports: https://github.com/andrewthad/vex-unified/issues
 license: BSD-3-Clause
@@ -169,6 +169,7 @@
     EmptyPrimArray
   exposed-modules:
     Int
+    Int8
     Int16
     Int32
     Int64
@@ -216,22 +217,25 @@
     , Vector.Std.Word32
     , Vector.Std.Word64
     , Vector.Std.Word128
+    , Vector.Std.Int8
     , Vector.Std.Int16
     , Vector.Std.Int32
     , Vector.Std.Int
     , Vector.Eq.Int
     , Vector.Ord.Int
+    , Vector.Ord.Int8
     , Vector.Ord.Int16
     , Vector.Ord.Int32
     , Vector.Ord.Word8
     , Vector.Ord.Word16
     , Vector.Ord.Word32
     , Vector.Ord.Word64
-    , Vector.Eq.Int16
     , Vector.Eq.Word8
     , Vector.Eq.Word16
     , Vector.Eq.Word32
     , Vector.Eq.Word64
+    , Vector.Eq.Int8
+    , Vector.Eq.Int16
     , Vector.Eq.Int32
     , Vector.Masked.Word128
     , Vector.Masked.Word16
@@ -256,6 +260,7 @@
     , Vector.Zip.Word16.Lifted.Lifted
     , Vector.Zip.Lifted.Word16.Lifted
     , Vector.Zip.Bit.Bit.Bit
+    , Vector.Prim.Int8
     , Vector.Prim.Int32
     , Vector.Prim.Int64
     , Vector.Prim.Word8
@@ -280,6 +285,7 @@
     vext:indef (Vector as Vector.Std.Word32) requires (Element as Word32, Rep as Word32),
     vext:indef (Vector as Vector.Std.Word64) requires (Element as Word64, Rep as Word64),
     vext:indef (Vector as Vector.Std.Word128) requires (Element as Word128, Rep as Word128),
+    vext:indef (Vector as Vector.Std.Int8) requires (Element as Int8, Rep as Int8),
     vext:indef (Vector as Vector.Std.Int32) requires (Element as Int32, Rep as Int32),
     vext:indef (Vector as Vector.Std.Int16) requires (Element as Int16, Rep as Int16),
     vext:indef (Vector as Vector.Std.Int) requires (Element as Int, Rep as Int),
@@ -325,6 +331,7 @@
     vext:type-eq-indef (TypeEqVector as Vector.Std.Unlifted.Eq.ShortText)
       requires (Element as Unlifted, Rep as Unlifted, Type as ShortText),
     vext:ord-indef (OrdVector as Vector.Ord.Int) requires (Element as Int, Rep as Int),
+    vext:ord-indef (OrdVector as Vector.Ord.Int8) requires (Element as Int8, Rep as Int8),
     vext:ord-indef (OrdVector as Vector.Ord.Int16) requires (Element as Int16, Rep as Int16),
     vext:ord-indef (OrdVector as Vector.Ord.Word8) requires (Element as Word8, Rep as Word8),
     vext:ord-indef (OrdVector as Vector.Ord.Word16) requires (Element as Word16, Rep as Word16),
@@ -335,10 +342,12 @@
     vext:rep-eq-indef (EqVector as Vector.Eq.Int) requires (Element as Int, Rep as Int),
     vext:rep-eq-indef (EqVector as Vector.Eq.Int32) requires (Element as Int32, Rep as Int32),
     vext:rep-eq-indef (EqVector as Vector.Eq.Int16) requires (Element as Int16, Rep as Int16),
+    vext:rep-eq-indef (EqVector as Vector.Eq.Int8) requires (Element as Int8, Rep as Int8),
     vext:rep-eq-indef (EqVector as Vector.Eq.Word8) requires (Element as Word8, Rep as Word8),
     vext:rep-eq-indef (EqVector as Vector.Eq.Word16) requires (Element as Word16, Rep as Word16),
     vext:rep-eq-indef (EqVector as Vector.Eq.Word32) requires (Element as Word32, Rep as Word32),
     vext:rep-eq-indef (EqVector as Vector.Eq.Word64) requires (Element as Word64, Rep as Word64),
+    vext:prim-indef (PrimVector as Vector.Prim.Int8) requires (Element as Int8, Rep as Int8),
     vext:prim-indef (PrimVector as Vector.Prim.Int32) requires (Element as Int32, Rep as Int32),
     vext:prim-indef (PrimVector as Vector.Prim.Int64) requires (Element as Int64, Rep as Int64),
     vext:prim-indef (PrimVector as Vector.Prim.Word8) requires (Element as Word8, Rep as Word8),
@@ -449,6 +458,7 @@
     Vector.Word128
     Vector.Word128.Masked
     Vector.Int
+    Vector.Int8
     Vector.Int16
     Vector.Int32
     Vector.Int64
