diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,4 @@
+# Revision history for monoid-map
+
+## 2021-11-17
+* Added the code for Data.MonoidMap.
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright (c) 2021, Obsidian Systems LLC
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+
+    * Neither the name of Obsidian Systems LLC nor the names of other
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,5 @@
+# monoid-map
+[![Haskell](https://img.shields.io/badge/language-Haskell-orange.svg)](https://haskell.org) [![Hackage](https://img.shields.io/hackage/v/monoid-map.svg)](https://hackage.haskell.org/package/monoid-map) [![Hackage CI](https://matrix.hackage.haskell.org/api/v2/packages/monoid-map/badge)](https://matrix.hackage.haskell.org/#/package/monoid-map) [![Github CI](https://github.com/obsidiansystems/monoid-map/workflows/Haskell%20CI/badge.svg)](https://github.com/obsidiansystems/monoid-map/actions) [![BSD3 License](https://img.shields.io/badge/license-BSD3-blue.svg)](https://github.com/obsidiansystems/monoid-map/blob/master/LICENSE)
+
+
+Newtype wrapper around 'Data.Map.Monoidal.MonoidalMap' that has a correct 'Group' instance.
diff --git a/monoid-map.cabal b/monoid-map.cabal
new file mode 100644
--- /dev/null
+++ b/monoid-map.cabal
@@ -0,0 +1,37 @@
+cabal-version:      2.4
+name:               monoid-map
+version:            0.1.0.0
+synopsis:           Newtype wrapper around 'Data.Map.Monoidal.MonoidalMap' that has a correct 'Group' instance.
+description:
+  The 'Group' instance for Data.MonoidMap has a unique neutral element,
+  as compared to 'Data.Map.Monoidal.MonoidalMap'.
+
+homepage:           https://github.com/obsidiansystems/monoid-map
+bug-reports:
+  https://github.com/obsidiansystems/monoid-map/issues
+
+license:            BSD-3-Clause
+license-file:       LICENSE
+author:             Obsidian Systems LLC
+maintainer:         maintainer@obsidian.systems
+copyright:          (c) 2021 Obsidian Systems LLC
+category:           Data
+extra-source-files: CHANGELOG.md README.md
+
+library
+  exposed-modules:  Data.MonoidMap
+  other-extensions:
+    DeriveTraversable
+    FlexibleContexts
+    GeneralizedNewtypeDeriving
+    TypeFamilies
+    UndecidableInstances
+
+  build-depends:
+      appendmap
+    , base >= 4 && < 5
+    , monoidal-containers
+    , reflex
+    , witherable
+  hs-source-dirs:   src
+  default-language: Haskell2010
diff --git a/src/Data/MonoidMap.hs b/src/Data/MonoidMap.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/MonoidMap.hs
@@ -0,0 +1,55 @@
+-- | This module contains a newtype wrapper around 'Data.Map.Map' that has a
+-- correct 'Group' instance compared to the one for
+-- 'Data.Map.Monoidal.MonoidalMap', in that it has a unique neutral element.
+-- This comes with different constraints on the parameters (check the instances
+-- for 'Semigroup' and 'Monoid' of the corresponding data structures if you're
+-- interested).
+--
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE DeriveTraversable #-}
+{-# LANGUAGE UndecidableInstances #-} -- For (Eq (QueryResult q), Ord k, Query q) => Query (MonoidMap k q)
+{-# LANGUAGE StandaloneDeriving #-}
+module Data.MonoidMap where
+
+import Data.Witherable
+import Data.AppendMap
+import Data.Map.Monoidal (MonoidalMap)
+import Data.Map.Monoidal as Map
+import Data.Semigroup (Semigroup, (<>))
+import Reflex (Query, QueryResult, crop, Group(..), Additive)
+
+-- | Newtype wrapper around Data.Map.Monoidal.MonoidalMap
+newtype MonoidMap k v = MonoidMap { unMonoidMap :: MonoidalMap k v }
+  deriving (Show, Eq, Ord, Foldable, Functor, Traversable)
+
+deriving instance Filterable (MonoidalMap k) => Filterable (MonoidMap k)
+
+-- | Convert a MonoidalMap into a MonoidMap
+monoidMap :: (Ord k, Eq v, Monoid v) => MonoidalMap k v -> MonoidMap k v
+monoidMap = MonoidMap . Map.filter (/= mempty)
+
+instance (Eq (QueryResult q), Ord k, Query q) => Query (MonoidMap k q) where
+  type QueryResult (MonoidMap k q) = MonoidMap k (QueryResult q)
+  crop (MonoidMap q) (MonoidMap qr) =
+    -- This assumes that the query result of a null query should be null
+    monoidMap $ Map.intersectionWith crop q qr
+
+instance (Monoid a, Eq a, Ord k) => Semigroup (MonoidMap k a) where
+  MonoidMap a <> MonoidMap b =
+    let combine _ a' b' =
+          let c = a' `mappend` b'
+          in if c == mempty
+               then Nothing
+               else Just c
+    in MonoidMap $ Map.mergeWithKey combine id id a b
+
+instance (Ord k, Monoid a, Eq a) => Monoid (MonoidMap k a) where
+  mempty = MonoidMap Map.empty
+  mappend = (<>)
+
+instance (Ord k, Monoid a, Eq a, Group a) => Group (MonoidMap k a) where
+  negateG = fmap negateG
+
+instance (Ord k, Monoid a, Eq a, Group a, Additive a) => Additive (MonoidMap k a)
