diff --git a/CHANGELOG.markdown b/CHANGELOG.markdown
--- a/CHANGELOG.markdown
+++ b/CHANGELOG.markdown
@@ -1,3 +1,8 @@
+1.9.0
+====
+
+  * Added comment syntax (https://github.com/supki/aeson-match-qq/pull/43)
+
 1.8.0
 ====
 
@@ -17,7 +22,7 @@
 
   * Implemented `[...]` and `{...}` as shortcuts to `_ : array` and `_ : object` respectively (https://github.com/supki/aeson-match-qq/pull/34)
 
-  * Some work has been done on making match failures output understandable error messages (https://github.com/supki/aeson-match-qq/pull/37, https://github.com/supki/aeson-match-qq/pull/38, https://github.com/supki/aeson-match-qq/pull/39)
+  * Some work has been done on making match failures understandable (https://github.com/supki/aeson-match-qq/pull/37, https://github.com/supki/aeson-match-qq/pull/38, https://github.com/supki/aeson-match-qq/pull/39)
 
 1.6.1
 =====
@@ -27,7 +32,7 @@
 1.6.0
 =====
 
-  * Clarified ans simplified API some more.
+  * Clarified and simplified API some more.
 
 1.5.3
 =====
diff --git a/aeson-match-qq.cabal b/aeson-match-qq.cabal
--- a/aeson-match-qq.cabal
+++ b/aeson-match-qq.cabal
@@ -1,11 +1,11 @@
 cabal-version: 1.12
 
--- This file has been generated from package.yaml by hpack version 0.38.0.
+-- This file has been generated from package.yaml by hpack version 0.38.1.
 --
 -- see: https://github.com/sol/hpack
 
 name:           aeson-match-qq
-version:        1.8.0
+version:        1.9.0
 synopsis:       Declarative JSON matchers.
 description:    See README.markdown
 category:       Web
@@ -17,8 +17,7 @@
 license-file:   LICENSE
 build-type:     Simple
 tested-with:
-    GHC==9.6.5
-  , GHC==9.8.2
+    GHC==9.8.4
 extra-source-files:
     README.markdown
     CHANGELOG.markdown
diff --git a/src/Aeson/Match/QQ/Internal/Parse.hs b/src/Aeson/Match/QQ/Internal/Parse.hs
--- a/src/Aeson/Match/QQ/Internal/Parse.hs
+++ b/src/Aeson/Match/QQ/Internal/Parse.hs
@@ -267,12 +267,29 @@
 eof =
   Atto.endOfInput Atto.<?> "trailing garbage after a Matcher value"
 
--- This function has been stolen from aeson.
--- ref: https://hackage.haskell.org/package/aeson-1.4.6.0/docs/src/Data.Aeson.Parser.Internal.html#skipSpace
 spaces :: Atto.Parser ()
 spaces =
-  Atto.skipWhile (\b -> b == SpaceP || b == NewLineP || b == CRP || b == TabP)
-{-# INLINE spaces #-}
+  comment <|> whitespace <|> pure ()
+ where
+  comment = do
+    _ <- Atto.word8 HashP
+    b0 <- Atto.peekWord8
+    case b0 of
+      Just OpenCurlyBracketP ->
+        -- it's possible to rewrite this with Atto.lookAhead,
+        -- but I like this version better
+        fail "not a comment"
+      _ -> do
+        Atto.skipWhile (/= NewLineP)
+        spaces
+  whitespace = do
+    _ <- skipWhile1 (\b -> b == SpaceP || b == NewLineP || b == CRP || b == TabP)
+    spaces
+
+skipWhile1 :: (Word8 -> Bool) -> Atto.Parser ()
+skipWhile1 p = do
+  _ <- Atto.satisfy p
+  Atto.skipWhile p
 
 pattern HoleP, NP, FP, TP, DoubleQuoteP, DotP, CommaP, HashP :: Word8
 pattern HoleP = 95 -- '_'
diff --git a/test/Aeson/Match/QQ/Internal/ParseSpec.hs b/test/Aeson/Match/QQ/Internal/ParseSpec.hs
--- a/test/Aeson/Match/QQ/Internal/ParseSpec.hs
+++ b/test/Aeson/Match/QQ/Internal/ParseSpec.hs
@@ -71,6 +71,42 @@
     [qq| {foo: #{4 + 7 :: ToEncoding Int}} |] `shouldBe`
       Object Box {values = [("foo", [Ext (Aeson.Number 11)])], extra = False}
 
+  it "comments" $ do
+    [qq| _ # a nice hole |] `shouldBe` Sig AnyT False (Var "")
+    [qq|
+      [ 1
+      # , 2
+      , 3
+      ]
+    |] `shouldBe`
+      Array Box {values = [Number 1, Number 3], extra = False}
+    [qq|
+      [ 1 # one
+      , 2 # two
+      , 3 # three
+      ]
+    |] `shouldBe`
+      Array Box {values = [Number 1, Number 2, Number 3], extra = False}
+    [qq|
+      # it's an object!
+      { foo: 4
+      , bar: 7
+      }
+    |] `shouldBe`
+      Object Box {values = [("foo", [Number 4]), ("bar", [Number 7])], extra = False}
+    [qq|
+      # multiline
+      # comment
+      { foo: 4
+      # in the middle of
+      # object definition
+      , bar: 7
+      }
+      # and at the end
+      # too
+    |] `shouldBe`
+      Object Box {values = [("foo", [Number 4]), ("bar", [Number 7])], extra = False}
+
 newtype ToEncoding a = ToEncoding { unToEncoding :: a }
     deriving (Show, Eq, Num)
 
