diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,11 @@
 # Revision history for futhark-data
 
+## 1.1.0.0 -- 2022-05-02
+
+* String literals are now supported in the textual value format.
+
+* The `PutValue1` typeclass now has instances for `Text` and `ByteString`.
+
 ## 1.0.3.0 -- 2021-12-06
 
 * The `GetValue [t]` instance no longer produces an empty list on any
diff --git a/futhark-data.cabal b/futhark-data.cabal
--- a/futhark-data.cabal
+++ b/futhark-data.cabal
@@ -1,6 +1,6 @@
 cabal-version:      2.4
 name:               futhark-data
-version:            1.0.3.0
+version:            1.1.0.0
 synopsis:           An implementation of the Futhark data format.
 
 description: The Futhark compiler and its tools uses a simple external
diff --git a/src/Futhark/Data.hs b/src/Futhark/Data.hs
--- a/src/Futhark/Data.hs
+++ b/src/Futhark/Data.hs
@@ -160,7 +160,7 @@
 arrayText p [] vs =
   p $ SVec.head vs
 arrayText p (d : ds) vs =
-  "[" <> mconcat (intersperse separator $ map (arrayText p ds . slice) [0 .. d -1]) <> "]"
+  "[" <> mconcat (intersperse separator $ map (arrayText p ds . slice) [0 .. d - 1]) <> "]"
   where
     slice_size = product ds
     slice i = SVec.slice (i * slice_size) slice_size vs
@@ -172,7 +172,7 @@
 valueText :: Value -> T.Text
 valueText v
   | product (valueShape v) == 0 =
-    "empty(" <> dims <> primTypeText (valueElemType v) <> ")"
+      "empty(" <> dims <> primTypeText (valueElemType v) <> ")"
   where
     dims = mconcat $ map (brackets . T.pack . show) $ valueShape v
     brackets s = "[" <> s <> "]"
@@ -311,27 +311,27 @@
 valueElems :: Value -> [Value]
 valueElems v
   | n : ns <- valueShape v =
-    let k = product ns
-        slices mk vs =
-          [ mk (SVec.fromList ns) $
-              SVec.slice (k * i) k vs
-            | i <- [0 .. n -1]
-          ]
-     in case v of
-          I8Value _ vs -> slices I8Value vs
-          I16Value _ vs -> slices I16Value vs
-          I32Value _ vs -> slices I32Value vs
-          I64Value _ vs -> slices I64Value vs
-          U8Value _ vs -> slices U8Value vs
-          U16Value _ vs -> slices U16Value vs
-          U32Value _ vs -> slices U32Value vs
-          U64Value _ vs -> slices U64Value vs
-          F16Value _ vs -> slices F16Value vs
-          F32Value _ vs -> slices F32Value vs
-          F64Value _ vs -> slices F64Value vs
-          BoolValue _ vs -> slices BoolValue vs
+      let k = product ns
+          slices mk vs =
+            [ mk (SVec.fromList ns) $
+                SVec.slice (k * i) k vs
+              | i <- [0 .. n - 1]
+            ]
+       in case v of
+            I8Value _ vs -> slices I8Value vs
+            I16Value _ vs -> slices I16Value vs
+            I32Value _ vs -> slices I32Value vs
+            I64Value _ vs -> slices I64Value vs
+            U8Value _ vs -> slices U8Value vs
+            U16Value _ vs -> slices U16Value vs
+            U32Value _ vs -> slices U32Value vs
+            U64Value _ vs -> slices U64Value vs
+            F16Value _ vs -> slices F16Value vs
+            F32Value _ vs -> slices F32Value vs
+            F64Value _ vs -> slices F64Value vs
+            BoolValue _ vs -> slices BoolValue vs
   | otherwise =
-    []
+      []
 
 -- | A class for Haskell values that can be retrieved from 'Value'.
 -- This is a convenience facility - don't expect it to be fast.
@@ -346,55 +346,55 @@
 instance GetValue Bool where
   getValue (BoolValue shape vs)
     | [] <- SVec.toList shape =
-      Just $ vs SVec.! 0
+        Just $ vs SVec.! 0
   getValue _ = Nothing
 
 instance GetValue Int8 where
   getValue (I8Value shape vs)
     | [] <- SVec.toList shape =
-      Just $ vs SVec.! 0
+        Just $ vs SVec.! 0
   getValue _ = Nothing
 
 instance GetValue Int16 where
   getValue (I16Value shape vs)
     | [] <- SVec.toList shape =
-      Just $ vs SVec.! 0
+        Just $ vs SVec.! 0
   getValue _ = Nothing
 
 instance GetValue Int32 where
   getValue (I32Value shape vs)
     | [] <- SVec.toList shape =
-      Just $ vs SVec.! 0
+        Just $ vs SVec.! 0
   getValue _ = Nothing
 
 instance GetValue Int64 where
   getValue (I64Value shape vs)
     | [] <- SVec.toList shape =
-      Just $ vs SVec.! 0
+        Just $ vs SVec.! 0
   getValue _ = Nothing
 
 instance GetValue Word8 where
   getValue (U8Value shape vs)
     | [] <- SVec.toList shape =
-      Just $ vs SVec.! 0
+        Just $ vs SVec.! 0
   getValue _ = Nothing
 
 instance GetValue Word16 where
   getValue (U16Value shape vs)
     | [] <- SVec.toList shape =
-      Just $ vs SVec.! 0
+        Just $ vs SVec.! 0
   getValue _ = Nothing
 
 instance GetValue Word32 where
   getValue (U32Value shape vs)
     | [] <- SVec.toList shape =
-      Just $ vs SVec.! 0
+        Just $ vs SVec.! 0
   getValue _ = Nothing
 
 instance GetValue Word64 where
   getValue (U64Value shape vs)
     | [] <- SVec.toList shape =
-      Just $ vs SVec.! 0
+        Just $ vs SVec.! 0
   getValue _ = Nothing
 
 -- | A class for Haskell values that can be converted to 'Value'.
@@ -468,8 +468,8 @@
     where
       size = SVec.fromList [fromIntegral (BS.length bs)]
 
--- | Like 'PutValue', but only for scalars - which means it cannot
--- fail.
+-- | Like 'PutValue', but only for scalars and a few other simple
+-- things that cannot fail.
 class PutValue1 t where
   putValue1 :: t -> Value
 
@@ -496,3 +496,11 @@
 
 instance PutValue1 Word64 where
   putValue1 = U64Value mempty . SVec.singleton
+
+instance PutValue1 T.Text where
+  putValue1 = putValue1 . T.encodeUtf8
+
+instance PutValue1 BS.ByteString where
+  putValue1 bs = U8Value size $ byteStringToVector bs
+    where
+      size = SVec.fromList [fromIntegral (BS.length bs)]
diff --git a/src/Futhark/Data/Parser.hs b/src/Futhark/Data/Parser.hs
--- a/src/Futhark/Data/Parser.hs
+++ b/src/Futhark/Data/Parser.hs
@@ -24,7 +24,8 @@
 import Data.Void
 import Futhark.Data
 import Text.Megaparsec
-import Text.Megaparsec.Char.Lexer (signed)
+import Text.Megaparsec.Char (char)
+import Text.Megaparsec.Char.Lexer (charLiteral, signed)
 import Prelude hiding (exponent)
 
 -- | Parse the name of a primitive type.  Does *not* consume any
@@ -178,6 +179,10 @@
       "false" $> BoolValue mempty (SVec.singleton False)
     ]
 
+parseStringConst :: Parsec Void T.Text Value
+parseStringConst =
+  char '"' *> (putValue1 . T.pack <$> manyTill charLiteral (char '"'))
+
 lexeme :: Parsec Void T.Text () -> Parsec Void T.Text a -> Parsec Void T.Text a
 lexeme sep p = p <* sep
 
@@ -214,6 +219,7 @@
 parseValue sep =
   choice
     [ lexeme sep parsePrimValue,
+      lexeme sep parseStringConst,
       putValue' $ inBrackets sep (parseValue sep `sepBy` lexeme sep ","),
       lexeme sep $ "empty(" *> parseEmpty <* ")"
     ]
diff --git a/tests/Tests.hs b/tests/Tests.hs
--- a/tests/Tests.hs
+++ b/tests/Tests.hs
@@ -92,7 +92,7 @@
 
     shorten s
       | length s < maxlen = s
-      | otherwise = take (maxlen -3) s <> "..."
+      | otherwise = take (maxlen - 3) s <> "..."
 
     test s x =
       testCase ("Reading " <> shorten (show s)) $
@@ -124,6 +124,8 @@
       test "-f64.inf" $ scalar F64Value (-1 / 0),
       test "true" $ scalar BoolValue True,
       test "false" $ scalar BoolValue False,
+      test "\"foo\"" $ putValue1 ("foo" :: T.Text),
+      test "\"\\\"foo\\\"\"" $ putValue1 ("\"foo\"" :: T.Text),
       negtest "tr_ue",
       testProperty "parse random data" $
         \v ->
