diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,3 +1,9 @@
+0.2.1
+===
+
+- added Data instances
+
+
 0.2.0
 ===
 
diff --git a/markup-parse.cabal b/markup-parse.cabal
--- a/markup-parse.cabal
+++ b/markup-parse.cabal
@@ -1,6 +1,6 @@
 cabal-version: 3.0
 name: markup-parse
-version: 0.2.0.0
+version: 0.2.1.0
 license: BSD-3-Clause
 license-file: LICENSE
 copyright: Copyright, Tony Day, 2023-
@@ -11,78 +11,100 @@
 bug-reports: https://github.com/tonyday567/markup-parse/issues
 synopsis: A markup parser.
 description:
-    A markup parser and printer, from and to strict bytestrings, optimised for speed.
+  A markup parser and printer, from and to strict bytestrings, optimised for speed.
+
 build-type: Simple
 tested-with:
-    , GHC == 9.6.7
-    , GHC == 9.8.4
-    , GHC == 9.10.2
-    , GHC == 9.12.2
+  ghc ==9.6.7
+  ghc ==9.8.4
+  ghc ==9.10.2
+  ghc ==9.12.2
+
 extra-doc-files:
-    ChangeLog.md
-    other/*.html
-    other/*.svg
-    readme.md
+  ChangeLog.md
+  other/*.html
+  other/*.svg
+  readme.md
 
 source-repository head
-    type: git
-    location: https://github.com/tonyday567/markup-parse
+  type: git
+  location: https://github.com/tonyday567/markup-parse
 
 common ghc-options-exe-stanza
-    ghc-options:
-        -fforce-recomp
-        -funbox-strict-fields
-        -rtsopts
-        -threaded
+  ghc-options:
+    -fforce-recomp
+    -funbox-strict-fields
+    -rtsopts
+    -threaded
 
 common ghc-options-stanza
-    ghc-options:
-        -Wall
-        -Wcompat
-        -Wincomplete-record-updates
-        -Wincomplete-uni-patterns
-        -Wredundant-constraints
+  ghc-options:
+    -Wall
+    -Wcompat
+    -Wincomplete-record-updates
+    -Wincomplete-uni-patterns
+    -Wredundant-constraints
 
-common ghc2021-stanza
-    default-language: GHC2021
+common ghc2024-additions
+  default-extensions:
+    DataKinds
+    DerivingStrategies
+    DisambiguateRecordFields
+    ExplicitNamespaces
+    GADTs
+    LambdaCase
+    MonoLocalBinds
+    RoleAnnotations
 
+common ghc2024-stanza
+  if impl(ghc >=9.10)
+    default-language:
+      GHC2024
+  else
+    import: ghc2024-additions
+    default-language:
+      GHC2021
+
 library
-    import: ghc-options-stanza
-    import: ghc2021-stanza
-    hs-source-dirs: src
-    build-depends:
-        , base               >=4.14 && <5
-        , bytestring         >=0.11.3 && <0.13
-        , containers         >=0.6 && <0.9
-        , deepseq            >=1.4 && <1.6
-        , flatparse          >=0.3.5 && <0.6
-        , string-interpolate >=0.3 && <0.4
-        , these              >=1.1 && <1.3
-    exposed-modules:
-        MarkupParse
-        MarkupParse.Internal.FlatParse
+  import: ghc-options-stanza
+  import: ghc2024-stanza
+  hs-source-dirs: src
+  build-depends:
+    base >=4.14 && <5,
+    bytestring >=0.11.3 && <0.13,
+    containers >=0.6 && <0.9,
+    deepseq >=1.4 && <1.6,
+    flatparse >=0.3.5 && <0.6,
+    string-interpolate >=0.3 && <0.4,
+    these >=1.1 && <1.3,
 
+  exposed-modules:
+    MarkupParse
+    MarkupParse.Internal.FlatParse
+
 test-suite doctests
-    import: ghc2021-stanza
-    main-is: doctests.hs
-    hs-source-dirs: test
-    build-depends:
-        , base             >=4.14 && <5
-        , doctest-parallel >=0.3 && <0.5
-    ghc-options: -threaded
-    type: exitcode-stdio-1.0
+  import: ghc2024-stanza
+  main-is: doctests.hs
+  hs-source-dirs: test
+  build-depends:
+    base >=4.14 && <5,
+    doctest-parallel >=0.3 && <0.5,
 
+  ghc-options: -threaded
+  type: exitcode-stdio-1.0
+
 test-suite markup-parse-diff
-    import: ghc-options-exe-stanza
-    import: ghc-options-stanza
-    import: ghc2021-stanza
-    main-is: markup-parse-diff.hs
-    hs-source-dirs: app
-    build-depends:
-        , base               >=4.14 && <5
-        , bytestring         >=0.11.3 && <0.13
-        , markup-parse
-        , tasty              >=1.2 && <1.6
-        , tasty-golden       >=2.3.1.1 && <2.4
-        , Diff               >=1.0 && <1.1
-    type: exitcode-stdio-1.0
+  import: ghc-options-exe-stanza
+  import: ghc-options-stanza
+  import: ghc2024-stanza
+  main-is: markup-parse-diff.hs
+  hs-source-dirs: app
+  build-depends:
+    Diff >=1.0 && <1.1,
+    base >=4.14 && <5,
+    bytestring >=0.11.3 && <0.13,
+    markup-parse,
+    tasty >=1.2 && <1.6,
+    tasty-golden >=2.3.1.1 && <2.4,
+
+  type: exitcode-stdio-1.0
diff --git a/readme.md b/readme.md
--- a/readme.md
+++ b/readme.md
@@ -1,33 +1,14 @@
-
-# Table of Contents
-
-1.  [markup-parse](#org813b686)
-2.  [Development](#org3d7b96c)
-3.  [Main Pipeline types](#orgb8f20ca)
-4.  [MarkupParse.Patch](#org3c16287)
-5.  [wiki diff test debug](#org25edc96)
-6.  [Reference](#org4a018da)
-    1.  [Prior Art](#org1ed6bdf)
-7.  [Performance](#org9b10723)
-    1.  [Profiling](#orgf660933)
-
-
-<a id="org813b686"></a>
-
 # markup-parse
 
 [![img](https://img.shields.io/hackage/v/markup-parse.svg)](https://hackage.haskell.org/package/markup-parse)
-[![img](https://github.com/tonyday567/markup-parse/workflows/haskell-ci/badge.svg)](https://github.com/tonyday567/markup-parse/actions?query=workflow%3Ahaskell-ci)
+[![img](https://github.com/tonyday567/markup-parse/actions/workflows/haskell-ci.yml/badge.svg)](https://github.com/tonyday567/markup-parse/actions/workflows/haskell-ci.yml)
 
 `markup-parse` parses and prints a subset of common XML & HTML structured data, from and to strict bytestrings
 
 
-<a id="org3d7b96c"></a>
-
 # Development
 
     :r
-    :set prompt "> "
     :set -Wno-type-defaults
     :set -Wno-name-shadowing
     :set -XOverloadedStrings
@@ -35,32 +16,22 @@
     :set -XQuasiQuotes
     import Control.Monad
     import MarkupParse
-    import MarkupParse.FlatParse
-    import MarkupParse.Patch
+    import MarkupParse.Internal.FlatParse
     import Data.ByteString qualified as B
     import Data.ByteString.Char8 qualified as C
     import Data.Map.Strict qualified as Map
     import Data.Function
     import FlatParse.Basic hiding (take)
     import Data.String.Interpolate
-    import Data.TreeDiff
     import Control.Monad
     bs <- B.readFile "other/line.svg"
     C.length bs
 
-    Preprocessing library for markup-parse-0.1.1..
-    GHCi, version 9.6.2: https://www.haskell.org/ghc/  :? for help
-    [1 of 3] Compiling MarkupParse.FlatParse ( src/MarkupParse/FlatParse.hs, interpreted )
-    [2 of 3] Compiling MarkupParse      ( src/MarkupParse.hs, interpreted )
-    [3 of 3] Compiling MarkupParse.Patch ( src/MarkupParse/Patch.hs, interpreted )
-    Ok, three modules loaded.
-    g
-    Ok, three modules loaded.
+    [1 of 2] Compiling MarkupParse.Internal.FlatParse ( src/MarkupParse/Internal/FlatParse.hs, interpreted ) [Flags changed]
+    Ok, two modules reloaded.
     7554
 
 
-<a id="orgb8f20ca"></a>
-
 # Main Pipeline types
 
     :t tokenize Html
@@ -78,28 +49,19 @@
     tokenize Html >=> gather Html >=> (normalize >>> pure) >=> degather Html >=> (fmap (detokenize Html) >>> pure)
       :: ByteString -> These [MarkupWarning] [ByteString]
 
-Round trip equality
 
-    m = markup_ Xml bs
-    m == (markup_ Xml $ markdown_ Compact Xml m)
-
-    True
+## tests
 
 
-<a id="org3c16287"></a>
-
-# MarkupParse.Patch
-
-Obviously, patch doesn&rsquo;t belong here long-term but has been very useful in testing and development.
+### Round trip equality
 
-    showPatch $ patch [1, 2, 3, 5] [0, 1, 2, 4, 6]
+    m = markup_ Xml bs
+    m == (markup_ Xml $ markdown_ Compact Xml m)
 
-    [+0, -3, +4, -5, +6]
+    True
 
 
-<a id="org25edc96"></a>
-
-# wiki diff test debug
+### wiki diff test debug
 
     bs <- B.readFile "other/Parsing - Wikipedia.html"
     m = markup_ Html bs
@@ -108,8 +70,6 @@
     True
 
 
-<a id="org4a018da"></a>
-
 # Reference
 
 [HTML Standard](https://html.spec.whatwg.org/#toc-syntax)
@@ -119,8 +79,6 @@
 [Extensible Markup Language (XML) 1.0 (Fifth Edition)](https://www.w3.org/TR/xml/)
 
 
-<a id="org1ed6bdf"></a>
-
 ## Prior Art
 
 [html-parse](https://hackage.haskell.org/package/html-parse) is an attoparsec-based parser for HTML. The HTML parsing here has referenced this parsing logic for HTML elements.
@@ -132,15 +90,12 @@
 [XMLParser](https://hackage.haskell.org/package/XMLParser) & [hexml](https://hackage.haskell.org/package/hexml) are parsec-based parsers.
 
 
-<a id="org9b10723"></a>
-
 # Performance
 
-The [perf](https://hackage.haskell.org/package/perf) library has been used to measure performance of the library.
 
-\`cabal bench\` runs the default benchmarking:
+## perf
 
-    cabal bench
+The [perf](https://hackage.haskell.org/package/perf) library has been used to measure performance of the library.
 
     Running 1 benchmarks...
     Benchmark markup-parse-speed: RUNNING...
@@ -155,8 +110,6 @@
     tokenize        time            8.59e5          8.67e5
     Benchmark markup-parse-speed: FINISH
 
-
-<a id="orgf660933"></a>
 
 ## Profiling
 
diff --git a/src/MarkupParse.hs b/src/MarkupParse.hs
--- a/src/MarkupParse.hs
+++ b/src/MarkupParse.hs
@@ -1,6 +1,3 @@
-{-# LANGUAGE DeriveAnyClass #-}
-{-# LANGUAGE DerivingStrategies #-}
-{-# LANGUAGE LambdaCase #-}
 {-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE QuasiQuotes #-}
 {-# LANGUAGE TemplateHaskell #-}
@@ -103,6 +100,7 @@
 import Data.ByteString (ByteString)
 import Data.ByteString.Char8 qualified as B
 import Data.Char hiding (isDigit)
+import Data.Data
 import Data.Foldable
 import Data.Function
 import Data.List qualified as List
@@ -172,17 +170,21 @@
 -- The xml parsing logic is based on the XML productions found in https://www.w3.org/TR/xml/
 --
 -- The html parsing was based on a reading of <https://hackage.haskell.org/package/html-parse html-parse>, but ignores the various '\x00' to '\xfffd' & eof directives that form part of the html standards.
-data Standard = Html | Xml deriving (Eq, Show, Ord, Generic, NFData)
+data Standard = Html | Xml
+  deriving stock (Eq, Ord, Show, Generic, Data)
 
+instance NFData Standard
+
 -- | A list of 'Element's or 'Tree' 'Token's
 --
 -- >>> markup Html "<foo class=\"bar\">baz</foo>"
 -- That (Markup {elements = [Node {rootLabel = OpenTag StartTag "foo" [Attr {attrName = "class", attrValue = "bar"}], subForest = [Node {rootLabel = Content "baz", subForest = []}]}]})
 newtype Markup = Markup {elements :: [Element]}
-  deriving stock (Show, Eq, Ord, Generic)
-  deriving anyclass (NFData)
+  deriving stock (Eq, Ord, Show, Generic, Data)
   deriving newtype (Semigroup, Monoid)
 
+instance NFData Markup
+
 -- | markup-parse generally tries to continue on parse errors, and return what has/can still be parsed, together with any warnings.
 data MarkupWarning
   = -- | A tag ending with "/>" that is not an element of 'selfClosers' (Html only).
@@ -204,8 +206,10 @@
   | -- | Badly formed declaration
     BadDecl
   | MarkupParser ParserWarning
-  deriving (Eq, Show, Ord, Generic, NFData)
+  deriving (Eq, Ord, Show, Generic, Data)
 
+instance NFData MarkupWarning
+
 showWarnings :: [MarkupWarning] -> String
 showWarnings = List.nub >>> fmap show >>> unlines
 
@@ -284,8 +288,11 @@
 type NameTag = ByteString
 
 -- | Whether an opening tag is a start tag or an empty element tag.
-data OpenTagType = StartTag | EmptyElemTag deriving (Show, Ord, Eq, Generic, NFData)
+data OpenTagType = StartTag | EmptyElemTag
+  deriving (Eq, Ord, Show, Generic, Data)
 
+instance NFData OpenTagType
+
 -- | A Markup token. The term is borrowed from <https://www.w3.org/html/wg/spec/tokenization.html#tokenization HTML> standards but is used across 'Html' and 'Xml' in this library.
 --
 -- Note that the 'Token' type is used in two slightly different contexts:
@@ -332,8 +339,10 @@
     Decl !ByteString ![Attr]
   | -- | Contents of a doctype declaration.
     Doctype !ByteString
-  deriving (Show, Ord, Eq, Generic, NFData)
+  deriving (Eq, Ord, Show, Generic, Data)
 
+instance NFData Token
+
 -- | Escape a single character.
 escapeChar :: Char -> ByteString
 escapeChar '<' = "&lt;"
@@ -484,7 +493,7 @@
 -- >>> detokenize Html <$> tokenize_ Html [i|<input checked>|]
 -- ["<input checked=\"\">"]
 data Attr = Attr {attrName :: !AttrName, attrValue :: !AttrValue}
-  deriving (Generic, Show, Eq, Ord)
+  deriving (Eq, Ord, Show, Generic, Data)
 
 instance NFData Attr
 
@@ -544,7 +553,7 @@
   (Decl t as) -> bool [i|<?#{t}#{renderAttrs as}?>|] [i|<!#{t}!>|] (s == Html)
 
 -- | @Indented 0@ puts newlines in between the tags.
-data RenderStyle = Compact | Indented Int deriving (Eq, Show, Generic)
+data RenderStyle = Compact | Indented Int deriving (Eq, Ord, Show, Generic, Data)
 
 indentChildren :: RenderStyle -> [ByteString] -> [ByteString]
 indentChildren Compact = id
@@ -960,7 +969,13 @@
 --
 -- >>> runParserWarn (ws `cut` "no whitespace") "x"
 -- This (ParserError "no whitespace")
-data ParserWarning = ParserLeftover ByteString | ParserError ByteString | ParserUncaught deriving (Eq, Show, Ord, Generic, NFData)
+data ParserWarning
+  = ParserLeftover ByteString
+  | ParserError ByteString
+  | ParserUncaught
+  deriving (Eq, Ord, Show, Generic, Data)
+
+instance NFData ParserWarning
 
 -- | Run parser, returning leftovers and errors as 'ParserWarning's.
 --
diff --git a/src/MarkupParse/Internal/FlatParse.hs b/src/MarkupParse/Internal/FlatParse.hs
--- a/src/MarkupParse/Internal/FlatParse.hs
+++ b/src/MarkupParse/Internal/FlatParse.hs
@@ -1,5 +1,3 @@
-{-# LANGUAGE DeriveAnyClass #-}
-{-# LANGUAGE LambdaCase #-}
 {-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE TemplateHaskell #-}
 
