diff --git a/ChangeLog.md b/ChangeLog.md
new file mode 100644
--- /dev/null
+++ b/ChangeLog.md
@@ -0,0 +1,6 @@
+# Changelog for fcf-composite
+
+## v0.1.0.0
+
+* Add `ToComposite` and `FromComposite` FCF expressions.
+* Add `Union`, `Difference` and `Intersection` FCF expressions.
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright Daniel Firth (c) 2021
+
+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 Daniel Firth 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,26 @@
+# fcf-composite
+
+Fcf support for [composite](https://hackage.haskell.org/package/composite-base) records. This gives bidirection between a composite
+style `[s :-> a]` and `MapC s a` from
+[fcf-containers](https://hackage.haskell.org/package/fcf-containers).
+
+Using this we can compute record types via the Map
+[operations](https://hackage.haskell.org/package/fcf-containers-0.6.0/docs/Fcf-Data-MapC.html)
+in Fcf.
+
+```{.haskell}
+data Difference :: [Type] -> [Type] -> Exp [Type]
+
+type instance Eval (Difference xs ys) = Eval (ToComposite =<< Fcf.Data.MapC.Difference (Eval (FromComposite xs)) (Eval (FromComposite ys)))
+
+type A = ["a" :-> Int, "b" :-> String, "c" :-> ()]
+
+type B = ["a" :-> Int, "c" :-> ()]
+
+myRec :: Record (Eval (Difference A B))
+myRec = "foo" :*: RNil -- checks!
+```
+
+Note: Since `ToComposite` and `FromComposite` use `ToList` and `FromList` from
+Fcf.Data.MapC, then the fields will always be returned in alphabetical order
+according to the symbol name, so you may need to use `rcast`.
diff --git a/fcf-composite.cabal b/fcf-composite.cabal
new file mode 100644
--- /dev/null
+++ b/fcf-composite.cabal
@@ -0,0 +1,38 @@
+cabal-version: 1.12
+
+-- This file has been generated from package.yaml by hpack version 0.34.4.
+--
+-- see: https://github.com/sol/hpack
+
+name:           fcf-composite
+version:        0.1.0.0
+synopsis:       Type-level computation for composite using first-class-families.
+description:    Type-level computation for composite using first-class-families.
+category:       Composite, Types
+author:         Daniel Firth
+maintainer:     dan.firth@homtopic.tech
+copyright:      Daniel Firth
+license:        MIT
+license-file:   LICENSE
+build-type:     Simple
+extra-source-files:
+    README.md
+    ChangeLog.md
+
+source-repository head
+  type: git
+  location: https://gitlab.homotopic.tech/haskell/fcf-composite
+
+library
+  exposed-modules:
+      Composite.Fcf
+  other-modules:
+      Paths_fcf_composite
+  hs-source-dirs:
+      src
+  build-depends:
+      base >=4.7 && <5
+    , composite-base >=0.7.0.0 && <0.8
+    , fcf-containers >=0.5.0 && <0.7
+    , first-class-families >=0.8.0.0 && <0.9
+  default-language: Haskell2010
diff --git a/src/Composite/Fcf.hs b/src/Composite/Fcf.hs
new file mode 100644
--- /dev/null
+++ b/src/Composite/Fcf.hs
@@ -0,0 +1,49 @@
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE TypeOperators #-}
+{-# LANGUAGE UndecidableInstances #-}
+
+module Composite.Fcf
+  ( FromCompositeS,
+    FromComposite,
+    ToCompositeS,
+    ToComposite,
+    Union,
+    Difference,
+    Intersection,
+  )
+where
+
+import Composite.Record
+import Data.Kind
+import Fcf
+import qualified Fcf.Data.MapC
+import GHC.TypeLits
+
+data FromCompositeS :: Type -> Exp (Symbol, Type)
+
+type instance Eval (FromCompositeS (s :-> x)) = '(s, x)
+
+data FromComposite :: [Type] -> Exp (Fcf.Data.MapC.MapC Symbol Type)
+
+type instance Eval (FromComposite x) = Eval (Fcf.Data.MapC.FromList =<< Fcf.Map FromCompositeS x)
+
+data ToCompositeS :: (Symbol, Type) -> Exp Type
+
+type instance Eval (ToCompositeS '(s, x)) = s :-> x
+
+data ToComposite :: Fcf.Data.MapC.MapC Symbol Type -> Exp [Type]
+
+type instance Eval (ToComposite x) = Eval (Fcf.Map ToCompositeS =<< Fcf.Data.MapC.ToList x)
+
+data Difference :: [Type] -> [Type] -> Exp [Type]
+
+type instance Eval (Difference xs ys) = Eval (ToComposite =<< Fcf.Data.MapC.Difference (Eval (FromComposite xs)) (Eval (FromComposite ys)))
+
+data Union :: [Type] -> [Type] -> Exp [Type]
+
+type instance Eval (Union xs ys) = Eval (ToComposite =<< Fcf.Data.MapC.Union (Eval (FromComposite xs)) (Eval (FromComposite ys)))
+
+data Intersection :: [Type] -> [Type] -> Exp [Type]
+
+type instance Eval (Intersection xs ys) = Eval (ToComposite =<< Fcf.Data.MapC.Intersection (Eval (FromComposite xs)) (Eval (FromComposite ys)))
