diff --git a/changelog.md b/changelog.md
--- a/changelog.md
+++ b/changelog.md
@@ -1,5 +1,9 @@
 # Revision history for sv-core
 
+## 0.3.1 -- 2019-01-04
+
+* Add `read` and `read'` decoders
+
 ## 0.3 -- 2018-09-26
 
 * Re-release 0.2.2 as 0.3 due to a change in error messages that
diff --git a/src/Data/Sv/Decode/Core.hs b/src/Data/Sv/Decode/Core.hs
--- a/src/Data/Sv/Decode/Core.hs
+++ b/src/Data/Sv/Decode/Core.hs
@@ -87,6 +87,10 @@
 , (==<<)
 , bindDecode
 
+-- * Building Decodes from Read
+, read
+, read'
+
 -- * Building Decodes from Readable
 , decodeRead
 , decodeRead'
@@ -121,7 +125,7 @@
 , makePositional
 ) where
 
-import Prelude hiding (either)
+import Prelude hiding (either, read)
 import qualified Prelude
 
 import Control.Lens (alaf)
@@ -157,6 +161,7 @@
 import qualified Data.Vector as V
 import Text.Parsec (Parsec)
 import qualified Text.Parsec as P (parse)
+import Text.Read (readMaybe)
 import qualified Text.Trifecta as Tri
 
 import Data.Sv.Decode.Error
@@ -253,19 +258,18 @@
 
 -- | Decode a UTF-8 'ByteString' field as a 'Double'
 --
--- This is much faster than 'rational' but can be less precise. If you're
--- not sure which to use, use 'rational'.
+-- This is currently the fastest but least precise way to decode doubles.
+-- 'rational' is more precise but slower. 'read' is the most precise, but
+-- slower still.
 --
--- See the documentation for 'Data.Text.Read.double' for more information.
+-- If you aren't sure which to use, use 'read'.
 double :: Decode' ByteString Double
 double = named "double"
 
 -- | Decode a UTF-8 'ByteString' as any 'Floating' type (usually 'Double')
 --
--- This is slower than 'double ' but more precise. If you're
--- not sure which to use, use 'rational'.
---
--- See the documentation for 'Data.Text.Read.double' for more information.
+-- This is slower than 'double' but more precise. It is not as precise as
+-- 'read'.
 rational :: Floating a => Decode' ByteString a
 rational = rat `o` utf8
   where
@@ -366,6 +370,18 @@
   in  contents >>== \s ->
     validateMaybe (UnknownCategoricalValue s (fmap snd as)) $
       alaf First foldMap (go s) as'
+
+-- | Build a 'Decode' from a 'Read' instance
+read :: Read a => Decode' ByteString a
+read = read' (const $ badDecode "read decoder failed")
+
+-- | Build a 'Decode' from a 'Read' instance.
+--
+-- This version takes a function which lets you build your own error message
+-- in the event of a failure.
+read' :: Read a => (ByteString -> DecodeValidation e a) -> Decode e ByteString a
+read' mkError = contents >>== \c ->
+  maybe (mkError c) pure $ readMaybe $ UTF8.toString c
 
 -- | Use the 'Readable' instance to try to decode the given value.
 decodeRead :: Readable a => Decode' ByteString a
diff --git a/sv-core.cabal b/sv-core.cabal
--- a/sv-core.cabal
+++ b/sv-core.cabal
@@ -1,5 +1,5 @@
 name:                sv-core
-version:             0.3
+version:             0.3.1
 license:             BSD3
 license-file:        LICENCE
 author:              George Wilson
@@ -28,8 +28,8 @@
 tested-with:         GHC == 7.10.3
                      , GHC == 8.0.2
                      , GHC == 8.2.2
-                     , GHC == 8.4.3
-                     , GHC == 8.6.1
+                     , GHC == 8.4.4
+                     , GHC == 8.6.3
 
 source-repository    head
   type:              git
@@ -49,18 +49,18 @@
   other-modules:       Data.Sv.Alien.Containers
   -- other-extensions:    
   build-depends:       attoparsec >= 0.12.1.4 && < 0.14
-                       , base >=4.8 && <5
-                       , bifunctors >= 5.1 && < 6
+                       , base >=4.8 && < 4.13
+                       , bifunctors >= 5.1 && < 5.6
                        , bytestring >= 0.9.1.10 && < 0.11
                        , containers >= 0.4 && < 0.7
                        , contravariant >= 1.2 && < 1.6
                        , deepseq >= 1.1 && < 1.5
-                       , lens >= 4 && < 5
+                       , lens >= 4 && < 4.18
                        , mtl >= 2.0.1 && < 2.3
                        , parsec >= 3.1 && < 3.2
-                       , profunctors >= 5.2.1 && < 6
+                       , profunctors >= 5.2.1 && < 5.4
                        , readable >= 0.3 && < 0.4
-                       , semigroupoids >= 5 && <6
+                       , semigroupoids >= 5 && < 5.4
                        , semigroups >= 0.18 && < 0.19
                        , text >= 1.0 && < 1.3
                        , transformers >= 0.2 && < 0.6
@@ -68,7 +68,7 @@
                        , utf8-string >= 1 && < 1.1
                        , validation >= 1 && < 1.1
                        , vector >= 0.10 && < 0.13
-                       , void >= 0.6 && < 1
+                       , void >= 0.6 && < 0.8
   hs-source-dirs:      src
   default-language:    Haskell2010
   ghc-options:
@@ -84,13 +84,13 @@
   default-language:
                        Haskell2010
   build-depends:
-                       base >=4.8 && <5
+                       base >=4.8 && < 4.13
                        , bytestring >= 0.9.1.10 && < 0.11
-                       , semigroupoids >= 5 && <6
+                       , semigroupoids >= 5 && < 5.4
                        , sv-core
                        , profunctors >= 5 && < 5.4
                        , semigroups >= 0.18 && < 0.19
-                       , tasty >= 0.11 && < 1.2
+                       , tasty >= 0.11 && < 1.3
                        , tasty-quickcheck >= 0.9 && < 0.11
                        , text >= 1.0 && < 1.3
                        , validation >= 1 && < 1.1
