diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -121,8 +121,13 @@
 [AWSLambda.Events.APIGateway](https://hackage.haskell.org/package/serverless-haskell/docs/AWSLambda-Events-APIGateway.html)
 in the handler to process them.
 
-[Serverless Offline] can be used for local testing of API Gateway requests.
+[Serverless Offline] can be used for local testing of API Gateway requests. You
+must use `--useDocker` flag so that the native Haskell runtime works correctly.
 
+When using [Serverless Offline], make sure that the project directory is
+world-readable, otherwise the started Docker container will be unable to access
+the handlers and all invocations will return HTTP status 502.
+
 ### Notes
 
 * Only AWS Lambda is supported at the moment. Other cloud providers would
@@ -153,8 +158,14 @@
 Integration test is only automatically run up to deployment due to the need for
 an AWS account. To run manually:
 
-* Ensure you have the required dependencies: `curl`, [jq], [NPM], `pwgen` and
-  [Stack].
+* Ensure you have the required dependencies:
+  - `curl`
+  - [jq]
+  - `libpcre` headers (`-devel` package or similar)
+  - [NPM]
+  - [`pkg-config`](pkg-config)
+  - `pwgen`
+  - [Stack]
 * Get an AWS account and add the access credentials into your shell environment.
 * Run `./integration-test/run.sh`. The exit code indicates success.
 * To verify just the packaging, without deployment, run
@@ -180,6 +191,7 @@
 [Docker]: https://www.docker.com/
 [jq]: https://stedolan.github.io/jq/
 [NPM]: https://www.npmjs.com/
+[pkg-config]: https://www.freedesktop.org/wiki/Software/pkg-config/
 [Serverless]: https://serverless.com/framework/
 [Serverless Offline]: https://github.com/dherault/serverless-offline
 [Stack]: https://haskellstack.org
diff --git a/serverless-haskell.cabal b/serverless-haskell.cabal
--- a/serverless-haskell.cabal
+++ b/serverless-haskell.cabal
@@ -1,13 +1,13 @@
 cabal-version: 1.12
 
--- This file has been generated from package.yaml by hpack version 0.31.2.
+-- This file has been generated from package.yaml by hpack version 0.33.0.
 --
 -- see: https://github.com/sol/hpack
 --
--- hash: a0188a30ab4b0a3456e1359270cfe59d4445645d2de25f44bc3c3a1ccdf9a551
+-- hash: 81b4069c39b4cebbf975a9e2d1fc55161e337ed88e6a6f0cf45373663399f0b5
 
 name:           serverless-haskell
-version:        0.10.5
+version:        0.11.2
 synopsis:       Deploying Haskell code onto AWS Lambda using Serverless
 description:    Utilities to help process the events from AWS Lambda when deployed with the serverless-haskell plugin.
 category:       AWS, Cloud, Network
@@ -54,11 +54,11 @@
     , base >=4.7 && <5
     , bytestring
     , case-insensitive
+    , http-client
     , http-types
     , iproute
     , lens
-    , network
-    , network-simple
+    , safe-exceptions
     , text
     , time
     , unix
@@ -92,12 +92,12 @@
     , case-insensitive
     , hspec
     , hspec-discover
+    , http-client
     , http-types
     , iproute
     , lens
-    , network
-    , network-simple
     , raw-strings-qq
+    , safe-exceptions
     , serverless-haskell
     , text
     , time
diff --git a/src/AWSLambda.hs b/src/AWSLambda.hs
--- a/src/AWSLambda.hs
+++ b/src/AWSLambda.hs
@@ -55,7 +55,8 @@
 handler to process them.
 
 <https://github.com/dherault/serverless-offline Serverless Offline> can be used
-for local testing of API Gateway requests.
+for local testing of API Gateway requests. You must use @--useDocker@ flag so
+that the native Haskell runtime works correctly.
 
 = Additional features
 
@@ -70,17 +71,6 @@
     >     stackBuildArgs:
     >       - --pedantic
     >       - --allow-different-user
-
-* To start the executable with extra arguments, add them to @arguments@ under
-the function name:
-
-    > custom:
-    >   haskell:
-    >     arguments:
-    >       myfunc:
-    >         - --arg1
-    >         - --arg2
-    >         - arg3
 
 * Dependent system libraries not present in the AWS Lambda environment will be
 automatically uploaded along with the executable. Note that while statically
diff --git a/src/AWSLambda/Events/APIGateway.hs b/src/AWSLambda/Events/APIGateway.hs
--- a/src/AWSLambda/Events/APIGateway.hs
+++ b/src/AWSLambda/Events/APIGateway.hs
@@ -37,7 +37,6 @@
 import           Data.HashMap.Strict     (HashMap)
 import qualified Data.HashMap.Strict     as HashMap
 import           Data.IP
-import           Data.Text               (Text)
 import qualified Data.Text               as Text
 import           Data.Text.Encoding      (decodeUtf8, encodeUtf8)
 import           GHC.Generics            (Generic)
diff --git a/src/AWSLambda/Handler.hs b/src/AWSLambda/Handler.hs
--- a/src/AWSLambda/Handler.hs
+++ b/src/AWSLambda/Handler.hs
@@ -1,3 +1,5 @@
+{-# LANGUAGE OverloadedStrings #-}
+
 {-|
 Module      : AWSLambda.Handler
 Stability   : experimental
@@ -9,13 +11,16 @@
   ( lambdaMain
   ) where
 
-import Control.Exception (finally)
-import Control.Monad (void)
+import Control.Exception.Safe (SomeException(..), displayException, tryAny)
+import Control.Monad (forever, void)
 
+import Data.Aeson ((.=))
 import qualified Data.Aeson as Aeson
 
-import Data.ByteString (ByteString)
+import Data.Typeable (typeOf)
+
 import qualified Data.ByteString as ByteString
+import qualified Data.ByteString.Char8 as Char8
 import qualified Data.ByteString.Lazy as LBS
 
 import qualified Data.Text.Encoding as Text
@@ -23,9 +28,8 @@
 
 import GHC.IO.Handle (BufferMode(..), hSetBuffering)
 
-import Network.Simple.TCP (connect)
-import Network.Socket (close, withSocketsDo)
-import Network.Socket.ByteString (send)
+import Network.HTTP.Client
+import Network.HTTP.Types (HeaderName)
 
 import System.Environment (lookupEnv)
 import System.IO (stdout)
@@ -84,31 +88,57 @@
   => (event -> IO res) -- ^ Function to process the event
   -> IO ()
 lambdaMain act =
-  withSendResult $ \sendResult -> do
-    input <- ByteString.getLine
-    case Aeson.eitherDecodeStrict input of
+  runMain $ \input -> do
+    case Aeson.eitherDecode input of
       Left err -> error err
       Right event -> do
         result <- act event
-        sendResult $ LBS.toStrict $ Aeson.encode result
-        pure ()
+        pure $ Aeson.encode result
 
--- | Invoke an action with the method to output the result. If called by the
--- JavaScript wrapper, use the server started by it, otherwise use standard
--- output. Also set line buffering on standard output for AWS Lambda so the logs
--- are output in a timely manner.
-withSendResult :: ((ByteString -> IO ()) -> IO r) -> IO r
-withSendResult act = do
-  communicationPortString <- lookupEnv communicationPortEnv
-  case communicationPortString of
-    Just communicationPort -> do
+-- Process the incoming requests (using the AWS Lambda runtime interface or from the standard input).
+-- Also set line buffering on standard output for AWS Lambda so the logs are output in a timely manner.
+runMain :: (LBS.ByteString -> IO LBS.ByteString) -> IO ()
+runMain act = do
+  lambdaApiAddress <- lookupEnv lambdaApiAddressEnv
+  case lambdaApiAddress of
+    Just address -> do
       hSetBuffering stdout LineBuffering
-      withSocketsDo $
-        connect "127.0.0.1" communicationPort $ \(socket, _) ->
-          act (void . send socket) `finally` close socket
-    Nothing -> act $ Text.putStrLn . Text.decodeUtf8
+      manager <- newManager defaultManagerSettings
+      forever $ do
+        invocation <- httpLbs (invocationRequest address) manager
+        let input = responseBody invocation
+        let requestId = responseRequestId invocation
+        resultOrError <- tryAny $ act input
+        case resultOrError of
+          Right result -> void $ httpNoBody (resultRequest address requestId result) manager
+          Left exception -> void $ httpNoBody (errorRequest address requestId exception) manager
+    Nothing -> do
+      input <- LBS.fromStrict <$> ByteString.getLine
+      result <- act input
+      Text.putStrLn $ Text.decodeUtf8 $ LBS.toStrict result
 
--- | Environment variable signalling the port the JavaScript wrapper is
--- listening on
-communicationPortEnv :: String
-communicationPortEnv = "SERVERLESS_HASKELL_COMMUNICATION_PORT"
+lambdaApiAddressEnv :: String
+lambdaApiAddressEnv = "AWS_LAMBDA_RUNTIME_API"
+
+lambdaRequest :: String -> String -> Request
+lambdaRequest apiAddress rqPath = parseRequest_ $ "http://" ++ apiAddress ++ "/2018-06-01" ++ rqPath
+
+invocationRequest :: String -> Request
+invocationRequest apiAddress = (lambdaRequest apiAddress "/runtime/invocation/next") { responseTimeout = responseTimeoutNone }
+
+resultRequest :: String -> String -> LBS.ByteString -> Request
+resultRequest apiAddress requestId result = (lambdaRequest apiAddress $ "/runtime/invocation/" ++ requestId ++ "/response") { method = "POST", requestBody = RequestBodyLBS result }
+
+errorRequest :: String -> String -> SomeException -> Request
+errorRequest apiAddress requestId exception = (lambdaRequest apiAddress $ "/runtime/invocation/" ++ requestId ++ "/error") { method = "POST", requestBody = RequestBodyLBS body }
+  where
+    body = Aeson.encode $ Aeson.object [ "errorMessage" .= displayException exception, "errorType" .= exceptionType exception]
+
+exceptionType :: SomeException -> String
+exceptionType (SomeException e) = show (typeOf e)
+
+requestIdHeader :: HeaderName
+requestIdHeader = "Lambda-Runtime-Aws-Request-Id"
+
+responseRequestId :: Response a -> String
+responseRequestId = Char8.unpack . snd . head . filter (uncurry $ \h _ -> h == requestIdHeader) . responseHeaders
