diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -0,0 +1,5 @@
+# v0.1.0.0
+
+## Breaking
+
+- Migrate to `pqi` 0.1's record-of-functions redesign and switch to exporting the `adapter` value instead of the `Connection` type.
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -7,11 +7,11 @@
 backed by [`postgresql-libpq`](https://hackage.haskell.org/package/postgresql-libpq)
 (a binding to the C `libpq` library).
 
-`Pqi.Ffi.Connection` wraps a C-backed `PGconn` and provides an
-`IsConnection` instance whose every method is a near-mechanical delegation to
-the matching `Database.PostgreSQL.LibPQ` function. The only work is converting
-between this family's portable types (OIDs as `Word32`, indices as `Int32`,
-the shared enums) and `postgresql-libpq`'s C-specific newtypes.
+`Pqi.Ffi.adapter` produces `Pqi.Connection` values whose fields close over a
+C-backed `PGconn`, each a near-mechanical delegation to the matching
+`Database.PostgreSQL.LibPQ` function. The only work is converting between
+this family's portable types (OIDs as `Word32`, indices as `Int32`, the
+shared enums) and `postgresql-libpq`'s C-specific newtypes.
 
 This adapter is the **fidelity reference** for the `pqi` family: it is the
 oracle against which all other adapters are tested. The
diff --git a/pqi-ffi.cabal b/pqi-ffi.cabal
--- a/pqi-ffi.cabal
+++ b/pqi-ffi.cabal
@@ -1,6 +1,6 @@
 cabal-version: 3.0
 name: pqi-ffi
-version: 0.0.1.1
+version: 0.1.0.0
 category: Database, PostgreSQL
 synopsis: FFI adapter for pqi, backed by postgresql-libpq
 description:
@@ -95,7 +95,7 @@
     base >=4.11 && <5,
     bytestring >=0.10 && <0.13,
     postgresql-libpq >=0.11 && <0.12,
-    pqi ^>=0,
+    pqi ^>=0.1,
 
 test-suite ffi-test
   import: test
@@ -105,5 +105,5 @@
   build-depends:
     base >=4.11 && <5,
     hspec >=2.11 && <2.12,
-    pqi-conformance,
+    pqi-conformance ^>=0.1,
     pqi-ffi,
diff --git a/src/library/Pqi/Ffi.hs b/src/library/Pqi/Ffi.hs
--- a/src/library/Pqi/Ffi.hs
+++ b/src/library/Pqi/Ffi.hs
@@ -1,13 +1,16 @@
 -- | The FFI adapter, backed by @postgresql-libpq@.
 --
--- 'Connection' wraps the C-backed @PGconn@.
+-- 'adapter' bundles the three functions that produce a 'Pqi.Connection'
+-- whose fields are closures over the underlying C-backed @PGconn@.
+-- 'Pqi.Result' and 'Pqi.Cancel' values are constructed the same way, closing
+-- over the underlying @PGresult@\/@PGcancel@.
 --
--- Each method is a near-mechanical delegation to the matching
+-- Each closure is a near-mechanical delegation to the matching
 -- @Database.PostgreSQL.LibPQ@ function, with the only work being the
 -- conversion between this family's portable types (OIDs as 'Word32', indices
 -- as 'Int32', the shared enums) and @postgresql-libpq@'s C-specific newtypes.
 module Pqi.Ffi
-  ( Connection,
+  ( adapter,
   )
 where
 
@@ -15,141 +18,140 @@
 import qualified Pqi
 import Pqi.Ffi.Prelude
 
--- | A handle to a PostgreSQL connection backed by the C @libpq@ library.
-newtype Connection = Connection Pq.Connection
-
--- | A result handle backed by a C @PGresult@.
-newtype Result = Result Pq.Result
-
--- | A cancellation handle backed by a C @PGcancel@.
-newtype Cancel = Cancel Pq.Cancel
-
-instance Pqi.IsResult Result where
-  resultStatus (Result r) = fromExecStatus <$> Pq.resultStatus r
-  resultErrorMessage (Result r) = Pq.resultErrorMessage r
-  resultErrorField (Result r) field = Pq.resultErrorField r (toFieldCode field)
-  unsafeFreeResult (Result r) = Pq.unsafeFreeResult r
-  ntuples (Result r) = fromRow <$> Pq.ntuples r
-  nfields (Result r) = fromColumn <$> Pq.nfields r
-  fname (Result r) column = Pq.fname r (toColumn column)
-  fnumber (Result r) name = fmap fromColumn <$> Pq.fnumber r name
-  ftable (Result r) column = fromOid <$> Pq.ftable r (toColumn column)
-  ftablecol (Result r) column = fromColumn <$> Pq.ftablecol r (toColumn column)
-  fformat (Result r) column = fromFormat <$> Pq.fformat r (toColumn column)
-  ftype (Result r) column = fromOid <$> Pq.ftype r (toColumn column)
-  fmod (Result r) column = Pq.fmod r (toColumn column)
-  fsize (Result r) column = Pq.fsize r (toColumn column)
-  getvalue (Result r) row column = Pq.getvalue r (toRow row) (toColumn column)
-  getvalue' (Result r) row column = Pq.getvalue' r (toRow row) (toColumn column)
-  getisnull (Result r) row column = Pq.getisnull r (toRow row) (toColumn column)
-  getlength (Result r) row column = Pq.getlength r (toRow row) (toColumn column)
-  nparams (Result r) = fromIntegral <$> Pq.nparams r
-  paramtype (Result r) index = fromOid <$> Pq.paramtype r (fromIntegral index)
-  cmdStatus (Result r) = Pq.cmdStatus r
-  cmdTuples (Result r) = Pq.cmdTuples r
-
-instance Pqi.IsCancel Cancel where
-  cancel (Cancel handle) = Pq.cancel handle
-
-instance Pqi.IsConnection Connection where
-  type ResultOf Connection = Result
-  type CancelOf Connection = Cancel
-
-  connectdb conninfo = Connection <$> Pq.connectdb conninfo
-  connectStart conninfo = Connection <$> Pq.connectStart conninfo
-  connectPoll (Connection c) = fromPollingStatus <$> Pq.connectPoll c
-  newNullConnection = Connection <$> Pq.newNullConnection
-  isNullConnection (Connection c) = Pq.isNullConnection c
-  finish (Connection c) = Pq.finish c
-  reset (Connection c) = Pq.reset c
-  resetStart (Connection c) = Pq.resetStart c
-  resetPoll (Connection c) = fromPollingStatus <$> Pq.resetPoll c
-  db (Connection c) = Pq.db c
-  user (Connection c) = Pq.user c
-  pass (Connection c) = Pq.pass c
-  host (Connection c) = Pq.host c
-  port (Connection c) = Pq.port c
-  options (Connection c) = Pq.options c
-  status (Connection c) = fromConnStatus <$> Pq.status c
-  transactionStatus (Connection c) = fromTransactionStatus <$> Pq.transactionStatus c
-  parameterStatus (Connection c) name = Pq.parameterStatus c name
-  protocolVersion (Connection c) = Pq.protocolVersion c
-  serverVersion (Connection c) = Pq.serverVersion c
-  errorMessage (Connection c) = Pq.errorMessage c
-  socket (Connection c) = Pq.socket c
-  backendPID (Connection c) = fromIntegral <$> Pq.backendPID c
-  connectionNeedsPassword (Connection c) = Pq.connectionNeedsPassword c
-  connectionUsedPassword (Connection c) = Pq.connectionUsedPassword c
-
-  exec (Connection c) sql =
-    fmap Result <$> Pq.exec c sql
-  execParams (Connection c) sql params resultFormat =
-    fmap Result <$> Pq.execParams c sql (fmap (fmap toParam) params) (toFormat resultFormat)
-  prepare (Connection c) name sql paramTypes =
-    fmap Result <$> Pq.prepare c name sql (fmap (fmap toOid) paramTypes)
-  execPrepared (Connection c) name params resultFormat =
-    fmap Result <$> Pq.execPrepared c name (fmap (fmap toBoundParam) params) (toFormat resultFormat)
-  describePrepared (Connection c) name =
-    fmap Result <$> Pq.describePrepared c name
-  describePortal (Connection c) name =
-    fmap Result <$> Pq.describePortal c name
-
-  escapeStringConn (Connection c) = Pq.escapeStringConn c
-  escapeByteaConn (Connection c) = Pq.escapeByteaConn c
-  escapeIdentifier (Connection c) = Pq.escapeIdentifier c
-
-  sendQuery (Connection c) sql = Pq.sendQuery c sql
-  sendQueryParams (Connection c) sql params resultFormat =
-    Pq.sendQueryParams c sql (fmap (fmap toParam) params) (toFormat resultFormat)
-  sendPrepare (Connection c) name sql paramTypes =
-    Pq.sendPrepare c name sql (fmap (fmap toOid) paramTypes)
-  sendQueryPrepared (Connection c) name params resultFormat =
-    Pq.sendQueryPrepared c name (fmap (fmap toBoundParam) params) (toFormat resultFormat)
-  sendDescribePrepared (Connection c) name = Pq.sendDescribePrepared c name
-  sendDescribePortal (Connection c) name = Pq.sendDescribePortal c name
-  getResult (Connection c) = fmap Result <$> Pq.getResult c
-  consumeInput (Connection c) = Pq.consumeInput c
-  isBusy (Connection c) = Pq.isBusy c
-  setnonblocking (Connection c) nonBlocking = Pq.setnonblocking c nonBlocking
-  isnonblocking (Connection c) = Pq.isnonblocking c
-  setSingleRowMode (Connection c) = Pq.setSingleRowMode c
-  flush (Connection c) = fromFlushStatus <$> Pq.flush c
-
-  pipelineStatus (Connection c) = fromPipelineStatus <$> Pq.pipelineStatus c
-  enterPipelineMode (Connection c) = Pq.enterPipelineMode c
-  exitPipelineMode (Connection c) = Pq.exitPipelineMode c
-  pipelineSync (Connection c) = Pq.pipelineSync c
-  sendFlushRequest (Connection c) = Pq.sendFlushRequest c
-
-  getCancel (Connection c) = fmap Cancel <$> Pq.getCancel c
-
-  notifies (Connection c) = fmap fromNotify <$> Pq.notifies c
-  disableNoticeReporting (Connection c) = Pq.disableNoticeReporting c
-  enableNoticeReporting (Connection c) = Pq.enableNoticeReporting c
-  getNotice (Connection c) = Pq.getNotice c
+-- | The FFI adapter.
+adapter :: Pqi.Adapter
+adapter =
+  Pqi.Adapter
+    { Pqi.name = "pqi-ffi",
+      Pqi.connectdb = \conninfo -> mkConnection <$> Pq.connectdb conninfo,
+      Pqi.connectStart = \conninfo -> mkConnection <$> Pq.connectStart conninfo,
+      Pqi.newNullConnection = mkConnection <$> Pq.newNullConnection,
+      Pqi.unescapeBytea = \input -> Pq.unescapeBytea input
+    }
 
-  putCopyData (Connection c) value = fromCopyInResult <$> Pq.putCopyData c value
-  putCopyEnd (Connection c) reason = fromCopyInResult <$> Pq.putCopyEnd c reason
-  getCopyData (Connection c) nonBlocking = fromCopyOutResult <$> Pq.getCopyData c nonBlocking
+-- | Build a 'Pqi.Connection' whose fields close over the given
+-- @postgresql-libpq@ connection handle.
+mkConnection :: Pq.Connection -> Pqi.Connection
+mkConnection c =
+  Pqi.Connection
+    { Pqi.connectPoll = fromPollingStatus <$> Pq.connectPoll c,
+      Pqi.isNullConnection = Pq.isNullConnection c,
+      Pqi.finish = Pq.finish c,
+      Pqi.reset = Pq.reset c,
+      Pqi.resetStart = Pq.resetStart c,
+      Pqi.resetPoll = fromPollingStatus <$> Pq.resetPoll c,
+      Pqi.db = Pq.db c,
+      Pqi.user = Pq.user c,
+      Pqi.pass = Pq.pass c,
+      Pqi.host = Pq.host c,
+      Pqi.port = Pq.port c,
+      Pqi.options = Pq.options c,
+      Pqi.status = fromConnStatus <$> Pq.status c,
+      Pqi.transactionStatus = fromTransactionStatus <$> Pq.transactionStatus c,
+      Pqi.parameterStatus = \name -> Pq.parameterStatus c name,
+      Pqi.protocolVersion = Pq.protocolVersion c,
+      Pqi.serverVersion = Pq.serverVersion c,
+      Pqi.errorMessage = Pq.errorMessage c,
+      Pqi.socket = Pq.socket c,
+      Pqi.backendPID = fromIntegral <$> Pq.backendPID c,
+      Pqi.connectionNeedsPassword = Pq.connectionNeedsPassword c,
+      Pqi.connectionUsedPassword = Pq.connectionUsedPassword c,
+      Pqi.exec = \sql -> fmap mkResult <$> Pq.exec c sql,
+      Pqi.execParams = \sql params resultFormat ->
+        fmap mkResult <$> Pq.execParams c sql (fmap (fmap toParam) params) (toFormat resultFormat),
+      Pqi.prepare = \name sql paramTypes ->
+        fmap mkResult <$> Pq.prepare c name sql (fmap (fmap toOid) paramTypes),
+      Pqi.execPrepared = \name params resultFormat ->
+        fmap mkResult <$> Pq.execPrepared c name (fmap (fmap toBoundParam) params) (toFormat resultFormat),
+      Pqi.describePrepared = \name -> fmap mkResult <$> Pq.describePrepared c name,
+      Pqi.describePortal = \name -> fmap mkResult <$> Pq.describePortal c name,
+      Pqi.escapeStringConn = \s -> Pq.escapeStringConn c s,
+      Pqi.escapeByteaConn = \s -> Pq.escapeByteaConn c s,
+      Pqi.escapeIdentifier = \s -> Pq.escapeIdentifier c s,
+      Pqi.sendQuery = \sql -> Pq.sendQuery c sql,
+      Pqi.sendQueryParams = \sql params resultFormat ->
+        Pq.sendQueryParams c sql (fmap (fmap toParam) params) (toFormat resultFormat),
+      Pqi.sendPrepare = \name sql paramTypes ->
+        Pq.sendPrepare c name sql (fmap (fmap toOid) paramTypes),
+      Pqi.sendQueryPrepared = \name params resultFormat ->
+        Pq.sendQueryPrepared c name (fmap (fmap toBoundParam) params) (toFormat resultFormat),
+      Pqi.sendDescribePrepared = \name -> Pq.sendDescribePrepared c name,
+      Pqi.sendDescribePortal = \name -> Pq.sendDescribePortal c name,
+      Pqi.getResult = fmap mkResult <$> Pq.getResult c,
+      Pqi.consumeInput = Pq.consumeInput c,
+      Pqi.isBusy = Pq.isBusy c,
+      Pqi.setnonblocking = \nonBlocking -> Pq.setnonblocking c nonBlocking,
+      Pqi.isnonblocking = Pq.isnonblocking c,
+      Pqi.setSingleRowMode = Pq.setSingleRowMode c,
+      Pqi.flush = fromFlushStatus <$> Pq.flush c,
+      Pqi.pipelineStatus = fromPipelineStatus <$> Pq.pipelineStatus c,
+      Pqi.enterPipelineMode = Pq.enterPipelineMode c,
+      Pqi.exitPipelineMode = Pq.exitPipelineMode c,
+      Pqi.pipelineSync = Pq.pipelineSync c,
+      Pqi.sendFlushRequest = Pq.sendFlushRequest c,
+      Pqi.getCancel = fmap mkCancel <$> Pq.getCancel c,
+      Pqi.notifies = fmap fromNotify <$> Pq.notifies c,
+      Pqi.disableNoticeReporting = Pq.disableNoticeReporting c,
+      Pqi.enableNoticeReporting = Pq.enableNoticeReporting c,
+      Pqi.getNotice = Pq.getNotice c,
+      Pqi.putCopyData = \value -> fromCopyInResult <$> Pq.putCopyData c value,
+      Pqi.putCopyEnd = \reason -> fromCopyInResult <$> Pq.putCopyEnd c reason,
+      Pqi.getCopyData = \nonBlocking -> fromCopyOutResult <$> Pq.getCopyData c nonBlocking,
+      Pqi.loCreat = fmap fromOid <$> Pq.loCreat c,
+      Pqi.loCreate = \oid -> fmap fromOid <$> Pq.loCreate c (toOid oid),
+      Pqi.loImport = \path -> fmap fromOid <$> Pq.loImport c path,
+      Pqi.loImportWithOid = \path oid -> fmap fromOid <$> Pq.loImportWithOid c path (toOid oid),
+      Pqi.loExport = \oid path -> Pq.loExport c (toOid oid) path,
+      Pqi.loOpen = \oid mode -> fmap fromLibPQLoFd <$> Pq.loOpen c (toOid oid) mode,
+      Pqi.loWrite = \fd value -> Pq.loWrite c (toLibPQLoFd fd) value,
+      Pqi.loRead = \fd len -> Pq.loRead c (toLibPQLoFd fd) len,
+      Pqi.loSeek = \fd mode offset -> Pq.loSeek c (toLibPQLoFd fd) mode offset,
+      Pqi.loTell = \fd -> Pq.loTell c (toLibPQLoFd fd),
+      Pqi.loTruncate = \fd len -> Pq.loTruncate c (toLibPQLoFd fd) len,
+      Pqi.loClose = \fd -> Pq.loClose c (toLibPQLoFd fd),
+      Pqi.loUnlink = \oid -> Pq.loUnlink c (toOid oid),
+      Pqi.clientEncoding = Pq.clientEncoding c,
+      Pqi.setClientEncoding = \encoding -> Pq.setClientEncoding c encoding,
+      Pqi.setErrorVerbosity = \verbosity ->
+        fromVerbosity <$> Pq.setErrorVerbosity c (toVerbosity verbosity)
+    }
 
-  loCreat (Connection c) = fmap fromOid <$> Pq.loCreat c
-  loCreate (Connection c) oid = fmap fromOid <$> Pq.loCreate c (toOid oid)
-  loImport (Connection c) path = fmap fromOid <$> Pq.loImport c path
-  loImportWithOid (Connection c) path oid = fmap fromOid <$> Pq.loImportWithOid c path (toOid oid)
-  loExport (Connection c) oid path = Pq.loExport c (toOid oid) path
-  loOpen (Connection c) oid mode = fmap fromLibPQLoFd <$> Pq.loOpen c (toOid oid) mode
-  loWrite (Connection c) fd value = Pq.loWrite c (toLibPQLoFd fd) value
-  loRead (Connection c) fd len = Pq.loRead c (toLibPQLoFd fd) len
-  loSeek (Connection c) fd mode offset = Pq.loSeek c (toLibPQLoFd fd) mode offset
-  loTell (Connection c) fd = Pq.loTell c (toLibPQLoFd fd)
-  loTruncate (Connection c) fd len = Pq.loTruncate c (toLibPQLoFd fd) len
-  loClose (Connection c) fd = Pq.loClose c (toLibPQLoFd fd)
-  loUnlink (Connection c) oid = Pq.loUnlink c (toOid oid)
+-- | Build a 'Pqi.Result' whose fields close over the given
+-- @postgresql-libpq@ result handle.
+mkResult :: Pq.Result -> Pqi.Result
+mkResult r =
+  Pqi.Result
+    { Pqi.resultStatus = fromExecStatus <$> Pq.resultStatus r,
+      Pqi.resultErrorMessage = Pq.resultErrorMessage r,
+      Pqi.resultErrorField = \field -> Pq.resultErrorField r (toFieldCode field),
+      Pqi.unsafeFreeResult = Pq.unsafeFreeResult r,
+      Pqi.ntuples = fromRow <$> Pq.ntuples r,
+      Pqi.nfields = fromColumn <$> Pq.nfields r,
+      Pqi.fname = \column -> Pq.fname r (toColumn column),
+      Pqi.fnumber = \name -> fmap fromColumn <$> Pq.fnumber r name,
+      Pqi.ftable = \column -> fromOid <$> Pq.ftable r (toColumn column),
+      Pqi.ftablecol = \column -> fromColumn <$> Pq.ftablecol r (toColumn column),
+      Pqi.fformat = \column -> fromFormat <$> Pq.fformat r (toColumn column),
+      Pqi.ftype = \column -> fromOid <$> Pq.ftype r (toColumn column),
+      Pqi.fmod = \column -> Pq.fmod r (toColumn column),
+      Pqi.fsize = \column -> Pq.fsize r (toColumn column),
+      Pqi.getvalue = \row column -> Pq.getvalue' r (toRow row) (toColumn column),
+      Pqi.getvalue' = \row column -> Pq.getvalue' r (toRow row) (toColumn column),
+      Pqi.getisnull = \row column -> Pq.getisnull r (toRow row) (toColumn column),
+      Pqi.getlength = \row column -> Pq.getlength r (toRow row) (toColumn column),
+      Pqi.nparams = fromIntegral <$> Pq.nparams r,
+      Pqi.paramtype = \index -> fromOid <$> Pq.paramtype r (fromIntegral index),
+      Pqi.cmdStatus = Pq.cmdStatus r,
+      Pqi.cmdTuples = Pq.cmdTuples r
+    }
 
-  clientEncoding (Connection c) = Pq.clientEncoding c
-  setClientEncoding (Connection c) encoding = Pq.setClientEncoding c encoding
-  setErrorVerbosity (Connection c) verbosity =
-    fromVerbosity <$> Pq.setErrorVerbosity c (toVerbosity verbosity)
+-- | Build a 'Pqi.Cancel' whose field closes over the given
+-- @postgresql-libpq@ cancellation handle.
+mkCancel :: Pq.Cancel -> Pqi.Cancel
+mkCancel handle =
+  Pqi.Cancel
+    { Pqi.cancel = Pq.cancel handle
+    }
 
 -- * Type conversions
 
diff --git a/src/library/Pqi/Ffi/Prelude.hs b/src/library/Pqi/Ffi/Prelude.hs
--- a/src/library/Pqi/Ffi/Prelude.hs
+++ b/src/library/Pqi/Ffi/Prelude.hs
@@ -17,11 +17,11 @@
 import Data.Ord as Exports
 import Data.Traversable as Exports
 import Data.Word as Exports
-import System.IO as Exports (IO)
-import Text.Show as Exports
 import Prelude as Exports
   ( Enum (..),
     Integral (..),
     Num (..),
     fromIntegral,
   )
+import System.IO as Exports (IO)
+import Text.Show as Exports
diff --git a/src/test/Spec.hs b/src/test/Spec.hs
--- a/src/test/Spec.hs
+++ b/src/test/Spec.hs
@@ -4,11 +4,10 @@
 -- and tears the container down again.
 module Main (main) where
 
-import Data.Proxy (Proxy (..))
 import Pqi.Conformance (specs)
-import Pqi.Ffi (Connection)
-import Test.Hspec
+import qualified Pqi.Ffi
 import Prelude
+import Test.Hspec
 
 main :: IO ()
-main = hspec (specs (Proxy @Connection))
+main = hspec (specs Pqi.Ffi.adapter)
