diff --git a/airgql.cabal b/airgql.cabal
--- a/airgql.cabal
+++ b/airgql.cabal
@@ -5,7 +5,7 @@
 -- see: https://github.com/sol/hpack
 
 name:           airgql
-version:        0.7.1.2
+version:        0.7.1.3
 synopsis:       Automatically generate a GraphQL API for an SQLite database
 description:    AirGQL automatically generates a GraphQL API for SQLite databases.
                 It analyses the database schema
diff --git a/readme.md b/readme.md
--- a/readme.md
+++ b/readme.md
@@ -51,6 +51,15 @@
   - …
 ```
 
+Also set the `lib-only` flag in your `stack.yaml` file
+to avoid irrelevant errors:
+
+```yaml
+flags:
+  airgql:
+    lib-only: true
+```
+
 
 ## Usage
 
diff --git a/source/AirGQL/Config.hs b/source/AirGQL/Config.hs
--- a/source/AirGQL/Config.hs
+++ b/source/AirGQL/Config.hs
@@ -9,7 +9,7 @@
 import Data.Int (Int)
 
 
--- | The maximum number of results allowed for the graphql playground
+-- | The maximum number of results allowed for the GraphiQL playground
 maxGraphqlResultCount :: Int
 maxGraphqlResultCount = 10000
 
@@ -27,7 +27,6 @@
   }
 
 
--- | Configuration for Airsequel's Pro Plan
 defaultConfig :: Config
 defaultConfig =
   Config
diff --git a/source/AirGQL/ExternalAppContext.hs b/source/AirGQL/ExternalAppContext.hs
--- a/source/AirGQL/ExternalAppContext.hs
+++ b/source/AirGQL/ExternalAppContext.hs
@@ -60,8 +60,8 @@
 getExternalAppContext :: Text -> IO ExternalAppContext
 getExternalAppContext baseUrl = do
   sqlite <- lookupBinaryPath "sqlite3"
-  sqliteEnv <- lookupEnv "AIRSEQUEL_SQLITE_BIN"
-  sqliteLib <- lookupEnv "AIRSEQUEL_SQLITE_LIB"
+  sqliteEnv <- lookupEnv "AIRGQL_SQLITE_BIN"
+  sqliteLib <- lookupEnv "AIRGQL_SQLITE_LIB"
 
   pure $
     ExternalAppContext
diff --git a/source/AirGQL/GraphQL.hs b/source/AirGQL/GraphQL.hs
--- a/source/AirGQL/GraphQL.hs
+++ b/source/AirGQL/GraphQL.hs
@@ -840,10 +840,11 @@
 
 
 getMutationResponse
-  :: Text
+  :: AccessMode
+  -> Text
   -> [ColumnEntry]
   -> Out.Type IO
-getMutationResponse tableName columnEntries =
+getMutationResponse accessMode tableName columnEntries =
   Out.NamedObjectType $
     outObjectTypeToObjectType $
       OutObjectType
@@ -853,7 +854,7 @@
               tableName <> " mutation response description"
         , interfaceTypes = []
         , fields =
-            HashMap.fromList
+            HashMap.fromList $
               [
                 ( "affected_rows"
                 , let
@@ -878,43 +879,47 @@
                   in
                     ValueResolver field value
                 )
-              ,
-                ( "returning"
-                , let
-                    field :: Out.Field IO
-                    field =
-                      outFieldToField $
-                        OutField
-                          { descriptionMb =
-                              Just
-                                "Non null returning description"
-                          , fieldType =
-                              Out.NonNullListType $
-                                Out.NamedObjectType $
-                                  Out.ObjectType
-                                    "returning"
-                                    (Just "short desc")
-                                    []
-                                    ( HashMap.fromList $
-                                        colNamesWithValResolver columnEntries
-                                    )
-                          , arguments = HashMap.empty
-                          }
-
-                    value :: ReaderT Out.Context IO Value
-                    value = do
-                      context <- ask
-                      case context & Out.values of
-                        Object obj ->
-                          pure $
-                            fromMaybe (Object P.mempty) $
-                              HashMap.lookup "returning" obj
-                        _ -> pure $ Object P.mempty
-                  in
-                    ValueResolver field value
-                )
               , mutationTypeNameField tableName
               ]
+                <> case accessMode of
+                  WriteOnly -> []
+                  _ ->
+                    [
+                      ( "returning"
+                      , let
+                          field :: Out.Field IO
+                          field =
+                            outFieldToField $
+                              OutField
+                                { descriptionMb =
+                                    Just
+                                      "Non null seturning description"
+                                , fieldType =
+                                    Out.NonNullListType $
+                                      Out.NamedObjectType $
+                                        Out.ObjectType
+                                          "returning"
+                                          (Just "short desc")
+                                          []
+                                          ( HashMap.fromList $
+                                              colNamesWithValResolver columnEntries
+                                          )
+                                , arguments = HashMap.empty
+                                }
+
+                          value :: ReaderT Out.Context IO Value
+                          value = do
+                            context <- ask
+                            case context & Out.values of
+                              Object obj ->
+                                pure $
+                                  fromMaybe (Object P.mempty) $
+                                    HashMap.lookup "returning" obj
+                              _ -> pure $ Object P.mempty
+                        in
+                          ValueResolver field value
+                      )
+                    ]
         }
 
 
@@ -1085,10 +1090,11 @@
 mutationType
   :: Connection
   -> Integer
+  -> AccessMode
   -> Text
   -> [TableEntryRaw]
   -> IO (Maybe (Out.ObjectType IO))
-mutationType connection maxRowsPerTable dbId tables = do
+mutationType connection maxRowsPerTable accessMode dbId tables = do
   let
     documentation =
       "Available queries for database \"" <> dbId <> "\""
@@ -1206,7 +1212,7 @@
         outFieldToField $
           OutField
             { descriptionMb = Just "description"
-            , fieldType = getMutationResponse tableName columnEntries
+            , fieldType = getMutationResponse accessMode tableName columnEntries
             , arguments =
                 HashMap.fromList
                   [ ("objects", objectsType)
@@ -1520,7 +1526,7 @@
         outFieldToField $
           OutField
             { descriptionMb = Just $ "Provides entries from " <> tableName
-            , fieldType = getMutationResponse tableName columnEntries
+            , fieldType = getMutationResponse accessMode tableName columnEntries
             , arguments =
                 HashMap.fromList
                   [
@@ -1559,7 +1565,7 @@
         outFieldToField $
           OutField
             { descriptionMb = Just $ "Provides entries from " <> tableName
-            , fieldType = getMutationResponse tableName columnEntries
+            , fieldType = getMutationResponse accessMode tableName columnEntries
             , arguments =
                 HashMap.fromList
                   [
@@ -1659,6 +1665,7 @@
     mutationType
       connection
       schemaConf.maxRowsPerTable
+      schemaConf.accessMode
       dbId
       tables
 
diff --git a/source/AirGQL/Introspection.hs b/source/AirGQL/Introspection.hs
--- a/source/AirGQL/Introspection.hs
+++ b/source/AirGQL/Introspection.hs
@@ -27,6 +27,7 @@
   not,
   ($),
   (&),
+  (&&),
   (<&>),
   (>>=),
  )
@@ -73,6 +74,7 @@
   column_name_gql,
   datatype_gql,
   getColumns,
+  isOmittable,
   notnull,
   select_options,
  )
@@ -1217,7 +1219,7 @@
           colName
           "" -- TODO: Reactivate description when user can specify it
           [] -- No arguments
-          ( if columnEntry.notnull
+          ( if columnEntry.notnull && not columnEntry.isOmittable
               then ["NON_NULL", "SCALAR"]
               else ["SCALAR"]
           )
@@ -1326,6 +1328,10 @@
         ReadOnly -> Null
         WriteOnly -> obj
         ReadAndWrite -> obj
+      requiresRead obj = case accessMode of
+        ReadOnly -> Null
+        WriteOnly -> obj
+        ReadAndWrite -> obj
 
     pure $
       customRowTypes
@@ -1379,42 +1385,43 @@
                                       ]
                                 )
                               ]
-                        , Object $
-                            HashMap.fromList
-                              [ ("name", "returning")
-                              ,
-                                ( "type"
-                                , Object $
-                                    HashMap.fromList
-                                      [ ("kind", "NON_NULL")
-                                      ,
-                                        ( "ofType"
-                                        , Object $
-                                            HashMap.fromList
-                                              [ ("kind", "LIST")
-                                              ,
-                                                ( "ofType"
-                                                , Object $
-                                                    HashMap.fromList
-                                                      [ ("kind", "NON_NULL")
-                                                      ,
-                                                        ( "ofType"
-                                                        , Object $
-                                                            HashMap.fromList
-                                                              [ ("kind", "OBJECT")
-                                                              ,
-                                                                ( "name"
-                                                                , String $ doubleXEncodeGql table.name <> "_row"
-                                                                )
-                                                              ]
-                                                        )
-                                                      ]
-                                                )
-                                              ]
-                                        )
-                                      ]
-                                )
-                              ]
+                        , requiresRead $
+                            Object $
+                              HashMap.fromList
+                                [ ("name", "returning")
+                                ,
+                                  ( "type"
+                                  , Object $
+                                      HashMap.fromList
+                                        [ ("kind", "NON_NULL")
+                                        ,
+                                          ( "ofType"
+                                          , Object $
+                                              HashMap.fromList
+                                                [ ("kind", "LIST")
+                                                ,
+                                                  ( "ofType"
+                                                  , Object $
+                                                      HashMap.fromList
+                                                        [ ("kind", "NON_NULL")
+                                                        ,
+                                                          ( "ofType"
+                                                          , Object $
+                                                              HashMap.fromList
+                                                                [ ("kind", "OBJECT")
+                                                                ,
+                                                                  ( "name"
+                                                                  , String $ doubleXEncodeGql table.name <> "_row"
+                                                                  )
+                                                                ]
+                                                          )
+                                                        ]
+                                                  )
+                                                ]
+                                          )
+                                        ]
+                                  )
+                                ]
                         ]
                     )
                   ]
@@ -1578,7 +1585,7 @@
                   )
                 ,
                   ( "subscriptionType"
-                  , -- Airsequel does not yet support Subscriptions
+                  , -- AirGQL doesn't support Subscriptions yet
                     ValueResolver subscriptionTypeType $ pure Null
                   )
                 ,
diff --git a/source/AirGQL/Lib.hs b/source/AirGQL/Lib.hs
--- a/source/AirGQL/Lib.hs
+++ b/source/AirGQL/Lib.hs
@@ -135,7 +135,7 @@
               { errSQLType = "Object Type"
               , errHaskellType = "String"
               , errMessage =
-                  "\"" <> show sqlData <> "\" is not a vaild object type"
+                  "\"" <> show sqlData <> "\" is not a valid object type"
               }
         ]
 
@@ -337,6 +337,13 @@
         { name = getFirstName names
         , columns = [col_name]
         }
+  -- Primary keys are unique by default, even though they do not have an unique index
+  SQL.ColConstraintDef names (SQL.ColPrimaryKeyConstraint _) ->
+    Just $
+      UniqueConstraint
+        { name = getFirstName names
+        , columns = [col_name]
+        }
   _ -> Nothing
 
 
@@ -348,6 +355,13 @@
         , columns = P.fmap nameAsText columns
         }
     ]
+  -- Primary keys are unique by default, even though they do not have an unique index
+  SQL.TableConstraintDef names (SQL.TablePrimaryKeyConstraint columns) ->
+    [ UniqueConstraint
+        { name = getFirstName names
+        , columns = P.fmap nameAsText columns
+        }
+    ]
   SQL.TableColumnDef (SQL.ColumnDef col_name _ _ constraints) ->
     P.mapMaybe (getColumnUniqueConstraint (nameAsText col_name)) constraints
   _ -> []
@@ -779,12 +793,8 @@
         , datatype = "INTEGER"
         , datatype_gql = Just $ stringToGqlTypeName "Int"
         , select_options = P.Nothing
-        , -- While the rowid is actually NOT NULL,
-          -- it must be set to false here
-          -- to show in the GraphQL docs that it can be omitted
-          -- since it will be set automatically.
-          notnull = False
-        , isUnique = False
+        , notnull = True
+        , isUnique = True
         , isOmittable = True
         , isGenerated = False
         , dflt_value = P.Nothing
@@ -989,7 +999,7 @@
     -- TODO: Remove after
     --       https://github.com/JakeWheat/simple-sql-parser/issues/27
     & replaceWithSpace "if not exists" ""
-    -- TOOD: Remove after
+    -- TODO: Remove after
     --       https://github.com/JakeWheat/simple-sql-parser/issues/37
     & replaceCaseInsensitive "insert or abort " "insert "
     & replaceCaseInsensitive "insert or fail " "insert "
@@ -1188,7 +1198,7 @@
         , "nothing"
         , "notnull"
         , -- although "null" is on the official list of keywords, adding it here
-          --  seems to break "select NULL as ..." statemenets
+          --  seems to break "select NULL as ..." statements
           -- , "null"
           "nulls"
         , "of"
diff --git a/source/AirGQL/Utils.hs b/source/AirGQL/Utils.hs
--- a/source/AirGQL/Utils.hs
+++ b/source/AirGQL/Utils.hs
@@ -22,7 +22,6 @@
   getSqliteBinaryVersion,
   getSqliteEmbeddedVersion,
   headerJsonContent,
-  mainServerDb,
   quoteKeyword,
   quoteText,
   removeIfExists,
@@ -93,10 +92,6 @@
  )
 
 import AirGQL.ExternalAppContext (ExternalAppContext (sqlite))
-
-
-mainServerDb :: FilePath
-mainServerDb = "data" </> "airsequel.sqlite"
 
 
 getDbDir :: Text -> FilePath
diff --git a/tests/Spec.hs b/tests/Spec.hs
--- a/tests/Spec.hs
+++ b/tests/Spec.hs
@@ -115,7 +115,6 @@
 import AirGQL.Types.Utils (encodeToText)
 import AirGQL.Utils (
   getOrderOfLinkedList,
-  mainServerDb,
   removeIfExists,
   withRetryConn,
  )
@@ -272,8 +271,8 @@
                 , datatype = "INTEGER"
                 , datatype_gql = Just $ stringToGqlTypeName "Int"
                 , select_options = Nothing
-                , notnull = False
-                , isUnique = False
+                , notnull = True
+                , isUnique = True
                 , isOmittable = True
                 , isGenerated = False
                 , dflt_value = Nothing
@@ -478,7 +477,7 @@
                 , datatype_gql = Just $ stringToGqlTypeName "Int"
                 , select_options = Nothing
                 , notnull = False
-                , isUnique = False
+                , isUnique = True
                 , isOmittable = True
                 , isGenerated = False
                 , dflt_value = Nothing
@@ -3373,7 +3372,54 @@
 
       Ae.encode result `shouldBe` rmSpaces expected
 
+    it "doesn't allow writeonly tokens to return data" $ do
+      let dbName = "no-writeonly-return.db"
+      withTestDbConn shouldSaveDbs dbName $ \conn -> do
+        execute_
+          conn
+          [sql|
+            CREATE TABLE items (
+              id INTEGER PRIMARY KEY
+            )
+          |]
 
+      let
+        query :: Text
+        query =
+          [gql|
+              mutation items {
+                update_items(filter: { id: { eq: 0 }}, set: { id: 0 }) {
+                  returning { id }
+                }
+              }
+            |]
+
+        expected =
+          rmSpaces
+            [raw|
+              {
+                "data": null,
+                "errors": [{
+                  "locations": [{ "column":3, "line":2 }],
+                  "message": "Cannot query field \"update_items\" on type \"Mutation\"."
+                }]
+              }
+            |]
+
+      schema <- withRetryConn (unpack dbPath) $ \conn -> do
+        tables <- getTables conn
+        getDerivedSchema
+          defaultSchemaConf{accessMode = WriteOnly}
+          conn
+          dbPath
+          tables
+
+      Right response <-
+        graphql schema Nothing mempty query
+
+      Ae.encode response `shouldBe` expected
+
+
 deleteDbEntries :: Text -> IO ()
 deleteDbEntries databasePath = do
   conn <- open $ unpack databasePath
@@ -3386,8 +3432,6 @@
   cwd <- getWorkingDirectory
   createDirectoryIfMissing True (".." </> "data" </> "TEST" </> "data")
   changeWorkingDirectory (cwd </> ".." </> "data" </> "TEST")
-
-  removeIfExists mainServerDb
 
   removeIfExists $ unpack dbPath
 
