diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,13 @@
 # Changelog
 
+## 1.0.6.0 - 2020-02-27
+
+### Changed
+
+  - Don't quote simple strings containing spaces, e.g: hello world
+
+  - Single-quote dates (like '2020-02-27') and bools ('true' / 'false')
+
 ## 1.0.5.0 - 2019-11-30
 
 ### Fixed
diff --git a/aeson-yaml.cabal b/aeson-yaml.cabal
--- a/aeson-yaml.cabal
+++ b/aeson-yaml.cabal
@@ -1,7 +1,7 @@
 cabal-version: 1.12
 
 name:           aeson-yaml
-version:        1.0.5.0
+version:        1.0.6.0
 homepage:       https://github.com/clovyr/aeson-yaml
 bug-reports:    https://github.com/clovyr/aeson-yaml/issues
 author:         Patrick Nielsen
diff --git a/src/Data/Aeson/Yaml.hs b/src/Data/Aeson/Yaml.hs
--- a/src/Data/Aeson/Yaml.hs
+++ b/src/Data/Aeson/Yaml.hs
@@ -24,7 +24,7 @@
 import qualified Data.ByteString.Builder as ByteString.Builder
 import qualified Data.ByteString.Lazy as ByteString.Lazy
 import qualified Data.ByteString.Short as ByteString.Short
-import Data.Char (isDigit)
+import Data.Char (isAlpha, isDigit)
 import qualified Data.HashMap.Strict as HashMap
 import Data.List (intersperse, sortOn)
 import Data.Monoid ((<>), mconcat, mempty)
@@ -120,18 +120,28 @@
 
 encodeText :: Bool -> Bool -> Int -> Text -> Builder
 encodeText canMultiline alwaysQuote level s
+  -- s is a value, not a map key, and contains newlines; can be inserted
+  -- literally with `|` syntax
   | canMultiline && "\n" `Text.isSuffixOf` s = encodeLines level (Text.lines s)
-  | alwaysQuote && unquotable =
-    bs "'" <> b (Text.Encoding.encodeUtf8 s) <> bs "'"
+  -- s is a number, date, or boolString; single-quote
+  | Text.all isNumberOrDateRelated s || isBoolString = singleQuote
+  -- s should be quoted, AND s is not unsafe; single-quote
+  | alwaysQuote && unquotable = singleQuote
+  -- s should be quoted, OR s might be unsafe; double-quote
   | alwaysQuote || not unquotable = bl $ Data.Aeson.encode s
-  | otherwise = b (Text.Encoding.encodeUtf8 s)
+  -- otherwise; no quotes
+  | otherwise = noQuote
   where
-    unquotable =
-      s /= "" &&
-      not isSpecial &&
-      isSafeAscii (Text.head s) &&
-      not (Text.all isNumberOrDateRelated s) && Text.all isAllowed s
-    isSpecial
+    noQuote = b (Text.Encoding.encodeUtf8 s)
+    singleQuote = bs "'" <> noQuote <> bs "'"
+    headS = Text.head s
+    unquotable -- s is unquotable if all are True
+     =
+      s /= "" && -- s is not empty
+      Text.all isAllowed s && -- s consists of acceptable chars
+      (Data.Char.isAlpha headS || -- head of s is a char in A-Z or a-z or indicates a filepath
+       headS == '/')
+    isBoolString
       | Text.length s > 5 = False
       | otherwise =
         case Text.toLower s of
@@ -143,9 +153,7 @@
       (c >= 'A' && c <= 'Z') ||
       (c >= '0' && c <= '9') || c == '/' || c == '_' || c == '.' || c == '='
     isNumberOrDateRelated c = isDigit c || c == '.' || c == 'e' || c == '-'
-    isAllowed c
-      -- We don't include ' ' here to avoid sequences like " -" and ": "
-     = isSafeAscii c || c == '-' || c == ':'
+    isAllowed c = isSafeAscii c || c == '-' || c == ':' || c == ' '
 
 encodeLines :: Int -> [Text] -> Builder
 encodeLines level ls =
diff --git a/test/Test/Data/Aeson/Yaml.hs b/test/Test/Data/Aeson/Yaml.hs
--- a/test/Test/Data/Aeson/Yaml.hs
+++ b/test/Test/Data/Aeson/Yaml.hs
@@ -20,19 +20,19 @@
 
 import Data.Aeson.Yaml
 
-data TestCase =
-  TestCase
-    { tcName :: String
-    , tcInput :: Data.ByteString.Lazy.ByteString
-    , tcOutput :: Data.ByteString.Lazy.ByteString
-    , tcAlwaysQuote :: Bool
-    }
+data TestCase = TestCase
+  { tcName :: String
+  , tcInput :: Data.ByteString.Lazy.ByteString
+  , tcOutput :: Data.ByteString.Lazy.ByteString
+  , tcAlwaysQuote :: Bool
+  }
 
 testCases :: [TestCase]
-testCases = [tcDataTypes, tcNestedListsAndObjects, tcQuoted, tcEmptyList]
+testCases =
+  [tcDataTypes, tcNestedListsAndObjects, tcQuoted, tcEmptyList, tcHelloWorld]
 
 tcEmptyList :: TestCase
-tcEmptyList = 
+tcEmptyList =
   TestCase
     { tcName = "Empty root list"
     , tcInput = "[]"
@@ -57,6 +57,8 @@
    "dateString": "2038-01-19",
    "piString": "3.14",
    "expString": "1e3",
+   "leadingSpace" : " leading space",
+   "leadingSymbol" : "!leading symbol",
    "asteriskString": "*",
    "multiLine": "The first line is followed by the\nsecond line\n",
    "multiLineWithSpaces": "         This has extra\n     spaces at the beginning\n",
@@ -67,12 +69,14 @@
 |]
     , tcOutput =
         [s|asteriskString: "*"
-boolString: "true"
-dateString: "2038-01-19"
+boolString: 'true'
+dateString: '2038-01-19'
 emptyObject: {}
-expString: "1e3"
+expString: '1e3'
 isFalse: false
 isTrue: true
+leadingSpace: " leading space"
+leadingSymbol: "!leading symbol"
 list:
   - foo
   - bar
@@ -86,8 +90,8 @@
        spaces at the beginning
 notMultiline: "This won't be\nmulti-lined"
 nullValue: null
-numberString: "12345"
-piString: "3.14"
+numberString: '12345'
+piString: '3.14'
 "quoted ! key": true
 |]
     , tcAlwaysQuote = False
@@ -202,6 +206,39 @@
 'foo': 'bar'
 |]
     , tcAlwaysQuote = True
+    }
+
+tcHelloWorld :: TestCase
+tcHelloWorld =
+  TestCase
+    { tcName = "Hello World"
+    , tcInput =
+        [s|
+{ "image": "node 10.15.3"
+, "pipelines":
+  { "default":
+    [ { "step":
+        { "caches": []
+        , "name": "hello world"
+        , "script": [ "echo hello" ]
+        }
+      }
+    ]
+    
+  }
+}
+|]
+    , tcOutput =
+        [s|image: node 10.15.3
+pipelines:
+  default:
+    - step:
+        caches: []
+        name: hello world
+        script:
+          - echo hello
+|]
+    , tcAlwaysQuote = False
     }
 
 foo :: Data.Aeson.Value
