diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,5 +1,10 @@
 # Changelog for composite-dhall
 
+## v0.0.4.0
+
+* Change implementations to use DerivingVia.
+* Export `F` and `CoF` newtypes for deriving new `Rec f` instances.
+
 ## v0.0.3.0
 
 * Add `ToDhall` and `FromDhall` instances for `Rec []`
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -3,8 +3,11 @@
 `ToDhall` and `FromDhall` instances for
 [composite](https://hackage.haskell.org/package/composite-base) records.
 
-You can deserialise a normal dhall record such as
+You lets you use extensible records over any base functor that is representable
+in dhall.
 
+You can parse normal records:
+
 ```{.dhall}
 { a = "foo"
 , b = +5 }
@@ -23,7 +26,18 @@
 type MyRec = Record '[A, B]
 ```
 
-Similarly you can use a contravariant function as the base functor
+This also works for `Rec Maybe` and `Rec []`.
+
+```{.dhall}
+{ a = Just "foo"
+, b = Just +5 }
+```
+
+```{.haskell}
+type MyMaybeRec = Rec Maybe '[A, B]
+```
+
+Similarly you can use a contravariant functor as the base functor
 to parse a collection of templates for different types.
 
 ```{.dhall}
@@ -32,12 +46,10 @@
 }
 ```
 
-We use a DerivingVia to avoid overlapping instances in composite:
-
-```
-newtype Template a = Template (Op Text a)
+```{.haskell}
+newtype TextTemplate a = TextTemplate (Op Text a)
   deriving newtype (FromDhall)
 
-newtype Templates = Templates {unTemplates :: Rec Template '[A, B]}
+newtype TextTemplates = TextTemplates {unTemplates :: Rec Template '[A, B]}
   deriving (FromDhall) via (Rec (Op Text) '[A, B])
 ```
diff --git a/composite-dhall.cabal b/composite-dhall.cabal
--- a/composite-dhall.cabal
+++ b/composite-dhall.cabal
@@ -5,7 +5,7 @@
 -- see: https://github.com/sol/hpack
 
 name:           composite-dhall
-version:        0.0.3.0
+version:        0.0.4.0
 synopsis:       Dhall instances for composite records.
 description:    Dhall instances for composite records.
 category:       Dhall
@@ -36,7 +36,6 @@
     , composite-base >=0.7.0.0 && <0.8
     , dhall >=1.34.0 && <1.40
     , text >=1.0 && <1.4
-    , vinyl
   default-language: Haskell2010
 
 test-suite composite-dhall-test
@@ -55,5 +54,4 @@
     , tasty
     , tasty-hunit
     , text >=1.0 && <1.4
-    , vinyl
   default-language: Haskell2010
diff --git a/src/Composite/Dhall.hs b/src/Composite/Dhall.hs
--- a/src/Composite/Dhall.hs
+++ b/src/Composite/Dhall.hs
@@ -1,10 +1,10 @@
 {-# LANGUAGE DataKinds #-}
-{-# LANGUAGE DerivingStrategies #-}
+{-# LANGUAGE DerivingVia #-}
 {-# LANGUAGE FlexibleContexts #-}
 {-# LANGUAGE FlexibleInstances #-}
 {-# LANGUAGE GeneralisedNewtypeDeriving #-}
 {-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE QuantifiedConstraints #-}
+{-# LANGUAGE RankNTypes #-}
 {-# LANGUAGE RecordWildCards #-}
 {-# LANGUAGE ScopedTypeVariables #-}
 {-# LANGUAGE StandaloneDeriving #-}
@@ -13,7 +13,7 @@
 {-# LANGUAGE TypeOperators #-}
 {-# OPTIONS_GHC -fno-warn-incomplete-patterns #-}
 
-module Composite.Dhall (TextTemplate (TextTemplate, unTextTemplate), runTextTemplate) where
+module Composite.Dhall (TextTemplate (TextTemplate, unTextTemplate), runTextTemplate, F (unF), CoF (unCoF)) where
 
 import Composite.Record
 import Control.Applicative
@@ -42,77 +42,18 @@
   Dhall.Core.internalError
     (name <> ": Unexpected constructor: " <> Dhall.Core.pretty expression)
 
--- ToDhall
-
 instance D.ToDhall (Rec f '[]) where
   injectWith = pure (D.Encoder {..})
     where
       embed _ = RecordLit mempty
       declared = Record mempty
 
--- Identity
-
-instance (KnownSymbol s, D.ToDhall (Record xs), D.ToDhall x) => D.ToDhall (Record (s :-> x ': xs)) where
-  injectWith = do
-    let f :: s :-> x
-        f = undefined
-    let name = valName f
-    let D.Encoder embedL declaredL = D.inject
-    let D.Encoder embedR declaredR = D.inject
-    let embed (s :*: xs) = RecordLit (Dhall.Map.insert name (Dhall.Core.makeRecordField (embedL s)) mapR)
-          where
-            mapR = unsafeExpectRecordLit "Composite Record" $ embedR xs
-    let declared = Record (Dhall.Map.insert name (Dhall.Core.makeRecordField declaredL) mapR)
-          where
-            mapR = unsafeExpectRecord "Composite Record" declaredR
-    pure $ D.Encoder {..}
-
--- Maybe
-
-instance (KnownSymbol s, D.ToDhall (Rec Maybe xs), D.ToDhall x) => D.ToDhall (Rec Maybe (s :-> x ': xs)) where
-  injectWith = do
-    let f :: s :-> x
-        f = undefined
-    let name = valName f
-    let D.Encoder embedL declaredL = D.inject
-    let D.Encoder embedR declaredR = D.inject
-    let embed (s :^: xs) = RecordLit (Dhall.Map.insert name (Dhall.Core.makeRecordField (embedL s)) mapR)
-          where
-            mapR = unsafeExpectRecordLit "Composite Record" $ embedR xs
-    let declared = Record (Dhall.Map.insert name (Dhall.Core.makeRecordField declaredL) mapR)
-          where
-            mapR = unsafeExpectRecord "Composite Record" declaredR
-    pure $ D.Encoder {..}
-
--- List
-
-instance (KnownSymbol s, D.ToDhall (Rec [] xs), D.ToDhall x) => D.ToDhall (Rec [] (s :-> x ': xs)) where
-  injectWith = do
-    let f :: s :-> x
-        f = undefined
-    let name = valName f
-    let D.Encoder embedL declaredL = D.inject
-    let D.Encoder embedR declaredR = D.inject
-    let embed (s :^: xs) = RecordLit (Dhall.Map.insert name (Dhall.Core.makeRecordField (embedL s)) mapR)
-          where
-            mapR = unsafeExpectRecordLit "Composite Record" $ embedR xs
-    let declared = Record (Dhall.Map.insert name (Dhall.Core.makeRecordField declaredL) mapR)
-          where
-            mapR = unsafeExpectRecord "Composite Record" declaredR
-    pure $ D.Encoder {..}
-
----------------------------
-
--- FromDhall
-
 instance D.FromDhall (Rec f '[]) where
   autoWith _ = D.Decoder {..}
     where
       extract _ = pure RNil
       expected = pure $ Record (Dhall.Map.fromList [])
 
--- Identity
-
 instance (KnownSymbol s, D.FromDhall (Record xs), D.FromDhall x) => D.FromDhall (Record (s :-> x ': xs)) where
   autoWith = do
     let nL :: s :-> x
@@ -142,54 +83,65 @@
             _ -> die
     pure (D.Decoder extract expected)
 
--- Maybe
-
-instance (KnownSymbol s, D.FromDhall (Rec Maybe xs), D.FromDhall x) => D.FromDhall (Rec Maybe (s :-> x ': xs)) where
-  autoWith = do
-    let nL :: s :-> x
-        nL = undefined
-
-    let nameL = valName nL
-
-    D.Decoder extractL expectedL <- D.autoWith @(Maybe x)
+instance (KnownSymbol s, D.ToDhall (Record xs), D.ToDhall x) => D.ToDhall (Record (s :-> x ': xs)) where
+  injectWith = do
+    let f :: s :-> x
+        f = undefined
+    let name = valName f
+    let D.Encoder embedL declaredL = D.inject
+    let D.Encoder embedR declaredR = D.inject
+    let embed (s :*: xs) = RecordLit (Dhall.Map.insert name (Dhall.Core.makeRecordField (embedL s)) mapR)
+          where
+            mapR = unsafeExpectRecordLit "Composite Record" $ embedR xs
+    let declared = Record (Dhall.Map.insert name (Dhall.Core.makeRecordField declaredL) mapR)
+          where
+            mapR = unsafeExpectRecord "Composite Record" declaredR
+    pure $ D.Encoder {..}
 
-    D.Decoder extractR expectedR <- D.autoWith @(Rec Maybe xs)
+-- | Newtype wrapper for deriving `(Rec f xs)` where f is a `Functor` using DerivingVia.
+--
+-- @since 0.0.4.0
+newtype F f xs = F {unF :: Rec f xs}
 
-    let ktsR = unsafeExpectRecord "Composite Record" <$> expectedR
+-- | Newtype wrapper for deriving `(Rec f xs)` where f is `Contravariant` using DerivingVia.
+--
+-- @since 0.0.4.0
+newtype CoF f xs = CoF {unCoF :: Rec f xs}
 
-    let expected = Record <$> (Dhall.Map.insert nameL . Dhall.Core.makeRecordField <$> expectedL <*> ktsR)
-    let extract expression = do
-          let die = D.typeError expected expression
+deriving newtype instance D.FromDhall (F f '[])
 
-          case expression of
-            RecordLit kvs ->
-              case Dhall.Core.recordFieldValue <$> Dhall.Map.lookup nameL kvs of
-                Just expressionL ->
-                  liftA2
-                    (:^:)
-                    (extractL expressionL)
-                    (extractR expression)
-                _ -> die
-            _ -> die
-    pure (D.Decoder extract expected)
+deriving newtype instance D.FromDhall (CoF f '[])
 
--- List
+instance (KnownSymbol s, Functor f, D.ToDhall (F f xs), D.ToDhall (f x)) => D.ToDhall (F f (s :-> x ': xs)) where
+  injectWith = do
+    let f :: s :-> x
+        f = undefined
+    let name = valName f
+    let D.Encoder embedL declaredL = D.inject @(f x)
+    let D.Encoder embedR declaredR = D.inject @(F f xs)
+    let embed (F (s :^: xs)) = RecordLit (Dhall.Map.insert name (Dhall.Core.makeRecordField (embedL s)) mapR)
+          where
+            mapR = unsafeExpectRecordLit "Composite Rec f (Functor)" $ embedR (F xs)
+    let declared = Record (Dhall.Map.insert name (Dhall.Core.makeRecordField declaredL) mapR)
+          where
+            mapR = unsafeExpectRecord "Composite Rec f (Functor)" declaredR
+    pure $ D.Encoder {..}
 
-instance (KnownSymbol s, D.FromDhall (Rec [] xs), D.FromDhall x) => D.FromDhall (Rec [] (s :-> x ': xs)) where
-  autoWith = do
+instance (KnownSymbol s, Functor f, D.FromDhall (F f xs), D.FromDhall (f x)) => D.FromDhall (F f (s :-> x ': xs)) where
+  autoWith opts =
     let nL :: s :-> x
         nL = undefined
 
-    let nameL = valName nL
+        nameL = valName nL
 
-    D.Decoder extractL expectedL <- D.autoWith @[x]
+        D.Decoder extractL expectedL = D.autoWith @(f x) opts
 
-    D.Decoder extractR expectedR <- D.autoWith @(Rec [] xs)
+        D.Decoder extractR expectedR = unF <$> D.autoWith @(F f xs) opts
 
-    let ktsR = unsafeExpectRecord "Composite Record" <$> expectedR
+        ktsR = unsafeExpectRecord "Composite Rec f (Functor)" <$> expectedR
 
-    let expected = Record <$> (Dhall.Map.insert nameL . Dhall.Core.makeRecordField <$> expectedL <*> ktsR)
-    let extract expression = do
+        expected = Record <$> (Dhall.Map.insert nameL . Dhall.Core.makeRecordField <$> expectedL <*> ktsR)
+        extract expression = do
           let die = D.typeError expected expression
 
           case expression of
@@ -202,27 +154,23 @@
                     (extractR expression)
                 _ -> die
             _ -> die
-    pure (D.Decoder extract expected)
-
--- Op
-
-deriving newtype instance (D.FromDhall b, D.ToDhall x) => D.FromDhall (Op b x)
+     in F <$> D.Decoder extract expected
 
-instance (KnownSymbol s, D.FromDhall (Rec (Op b) xs), D.FromDhall b, D.ToDhall x) => D.FromDhall (Rec (Op b) (s :-> x ': xs)) where
-  autoWith = do
+instance (KnownSymbol s, D.FromDhall (CoF f xs), Contravariant f, D.FromDhall (f x)) => D.FromDhall (CoF f (s :-> x ': xs)) where
+  autoWith opts =
     let nL :: s :-> x
         nL = undefined
 
-    let nameL = valName nL
+        nameL = valName nL
 
-    D.Decoder extractL expectedL <- D.autoWith @(Op b x)
+        D.Decoder extractL expectedL = D.autoWith @(f x) opts
 
-    D.Decoder extractR expectedR <- D.autoWith @(Rec (Op b) xs)
+        D.Decoder extractR expectedR = unCoF <$> D.autoWith @(CoF f xs) opts
 
-    let ktsR = unsafeExpectRecord "Composite Record" <$> expectedR
+        ktsR = unsafeExpectRecord "Composite Rec f (Contravariant)" <$> expectedR
 
-    let expected = Record <$> (Dhall.Map.insert nameL . Dhall.Core.makeRecordField <$> expectedL <*> ktsR)
-    let extract expression = do
+        expected = Record <$> (Dhall.Map.insert nameL . Dhall.Core.makeRecordField <$> expectedL <*> ktsR)
+        extract expression = do
           let die = D.typeError expected expression
 
           case expression of
@@ -235,72 +183,27 @@
                     (extractR expression)
                 _ -> die
             _ -> die
-    pure (D.Decoder extract expected)
+     in CoF <$> D.Decoder extract expected
 
--- Predicate
 deriving newtype instance (D.ToDhall x) => D.FromDhall (Predicate x)
 
-instance (KnownSymbol s, D.FromDhall (Rec Predicate xs), D.ToDhall x) => D.FromDhall (Rec Predicate (s :-> x ': xs)) where
-  autoWith = do
-    let nL :: s :-> x
-        nL = undefined
-
-    let nameL = valName nL
-
-    D.Decoder extractL expectedL <- D.autoWith @(Predicate x)
-
-    D.Decoder extractR expectedR <- D.autoWith @(Rec Predicate xs)
-
-    let ktsR = unsafeExpectRecord "Composite Record" <$> expectedR
-
-    let expected = Record <$> (Dhall.Map.insert nameL . Dhall.Core.makeRecordField <$> expectedL <*> ktsR)
-    let extract expression = do
-          let die = D.typeError expected expression
-
-          case expression of
-            RecordLit kvs ->
-              case Dhall.Core.recordFieldValue <$> Dhall.Map.lookup nameL kvs of
-                Just expressionL ->
-                  liftA2
-                    (:&)
-                    (contramap getVal <$> extractL expressionL)
-                    (extractR expression)
-                _ -> die
-            _ -> die
-    pure (D.Decoder extract expected)
-
--- Equivalence
-
 deriving newtype instance (D.ToDhall x) => D.FromDhall (Equivalence x)
 
-instance (KnownSymbol s, D.FromDhall (Rec Equivalence xs), D.ToDhall x) => D.FromDhall (Rec Equivalence (s :-> x ': xs)) where
-  autoWith = do
-    let nL :: s :-> x
-        nL = undefined
+deriving newtype instance (D.FromDhall b, D.ToDhall x) => D.FromDhall (Op b x)
 
-    let nameL = valName nL
+deriving via (F Maybe (s :-> x ': xs)) instance (KnownSymbol s, D.ToDhall (F Maybe xs), D.ToDhall x) => D.ToDhall (Rec Maybe (s :-> x ': xs))
 
-    D.Decoder extractL expectedL <- D.autoWith @(Equivalence x)
+deriving via (F [] (s :-> x ': xs)) instance (KnownSymbol s, D.ToDhall (F [] xs), D.ToDhall x) => D.ToDhall (Rec [] (s :-> x ': xs))
 
-    D.Decoder extractR expectedR <- D.autoWith @(Rec Equivalence xs)
+deriving via (F Maybe (s :-> x ': xs)) instance (KnownSymbol s, D.FromDhall (F Maybe xs), D.FromDhall x) => D.FromDhall (Rec Maybe (s :-> x ': xs))
 
-    let ktsR = unsafeExpectRecord "Composite Record" <$> expectedR
+deriving via (F [] (s :-> x ': xs)) instance (KnownSymbol s, D.FromDhall (F [] xs), D.FromDhall x) => D.FromDhall (Rec [] (s :-> x ': xs))
 
-    let expected = Record <$> (Dhall.Map.insert nameL . Dhall.Core.makeRecordField <$> expectedL <*> ktsR)
-    let extract expression = do
-          let die = D.typeError expected expression
+deriving via (CoF Predicate (s :-> x ': xs)) instance (KnownSymbol s, D.FromDhall (CoF Predicate xs), D.ToDhall x) => D.FromDhall (Rec Predicate (s :-> x ': xs))
 
-          case expression of
-            RecordLit kvs ->
-              case Dhall.Core.recordFieldValue <$> Dhall.Map.lookup nameL kvs of
-                Just expressionL ->
-                  liftA2
-                    (:&)
-                    (contramap getVal <$> extractL expressionL)
-                    (extractR expression)
-                _ -> die
-            _ -> die
-    pure (D.Decoder extract expected)
+deriving via (CoF Equivalence (s :-> x ': xs)) instance (KnownSymbol s, D.FromDhall (CoF Equivalence xs), D.ToDhall x) => D.FromDhall (Rec Equivalence (s :-> x ': xs))
+
+deriving via (CoF (Op b) (s :-> x ': xs)) instance (KnownSymbol s, D.FromDhall (CoF (Op b) xs), D.FromDhall b, D.ToDhall x) => D.FromDhall (Rec (Op b) (s :-> x ': xs))
 
 -- | The common case where a function from `a -> Text` can be used
 -- in a record.
