diff --git a/ChangeLog.md b/ChangeLog.md
new file mode 100644
--- /dev/null
+++ b/ChangeLog.md
@@ -0,0 +1,3 @@
+# Changelog for http2-grpc-types
+
+## Unreleased changes
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright Author name here (c) 2018
+
+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 Author name here 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,3 @@
+# http2-grpc-types
+
+A module to put in common HTTP2/gRPC types, values, and helpers.
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/http2-grpc-types.cabal b/http2-grpc-types.cabal
new file mode 100644
--- /dev/null
+++ b/http2-grpc-types.cabal
@@ -0,0 +1,43 @@
+-- This file has been generated from package.yaml by hpack version 0.28.2.
+--
+-- see: https://github.com/sol/hpack
+--
+-- hash: ac7deaf4e4e16246c07477c353a2f55ac558d8b90ae2a0682e21c1bfd613a057
+
+name:           http2-grpc-types
+version:        0.1.0.0
+synopsis:       Types for gRPC over HTTP2 common for client and servers.
+description:    Please see the README on GitHub at <https://github.com/lucasdicioccio/http2-grpc-types#readme>
+category:       Network
+homepage:       https://github.com/lucasdicioccio/http2-grpc-types#readme
+bug-reports:    https://github.com/lucasdicioccio/http2-grpc-types/issues
+author:         Lucas DiCioccio
+maintainer:     lucas@dicioccio.fr
+copyright:      2018 Lucas DiCioccio
+license:        BSD3
+license-file:   LICENSE
+build-type:     Simple
+cabal-version:  >= 1.10
+extra-source-files:
+    ChangeLog.md
+    README.md
+
+source-repository head
+  type: git
+  location: https://github.com/lucasdicioccio/http2-grpc-types
+
+library
+  exposed-modules:
+      Network.GRPC.HTTP2.Encoding
+      Network.GRPC.HTTP2.Types
+  other-modules:
+      Paths_http2_grpc_types
+  hs-source-dirs:
+      src
+  build-depends:
+      base >=4.7 && <5
+    , binary >=0.8.5 && <0.11
+    , bytestring >=0.10.8 && <0.11
+    , proto-lens >=0.3.1 && <0.4
+    , zlib
+  default-language: Haskell2010
diff --git a/src/Network/GRPC/HTTP2/Encoding.hs b/src/Network/GRPC/HTTP2/Encoding.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/GRPC/HTTP2/Encoding.hs
@@ -0,0 +1,113 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+-- | Module for GRPC binary encoding/decoding from and to binary messages.
+--
+-- So far, only "pure" compression algorithms are supported as we rely on
+-- 'Decoder' (resp. 'Builder') which run with no interleaved side-effects.
+module Network.GRPC.HTTP2.Encoding (
+  -- * Decoding.
+    decoder
+  , fromDecoder
+  , decodeInput
+  , decodeOutput
+  -- * Encoding.
+  , encode
+  , fromBuilder
+  , encodeInput
+  , encodeOutput
+  -- * Compression.
+  , Compression
+  , grpcCompressionHV
+  , uncompressed
+  , gzip
+  ) where
+
+import qualified Codec.Compression.GZip as GZip
+import           Data.Binary.Builder (Builder, toLazyByteString, fromByteString, singleton, putWord32be)
+import           Data.Binary.Get (getByteString, getInt8, getWord32be, runGetIncremental, Decoder(..))
+import           Data.ByteString.Char8 (ByteString)
+import qualified Data.ByteString.Char8 as ByteString
+import           Data.ByteString.Lazy (fromStrict, toStrict)
+import           Data.ProtoLens.Encoding (encodeMessage, decodeMessage)
+import           Data.ProtoLens.Message (Message)
+import           Data.ProtoLens.Service.Types (Service(..), HasMethod, HasMethodImpl(..))
+
+import           Network.GRPC.HTTP2.Types
+
+-- | Decoder for gRPC/HTTP2-encoded Protobuf messages.
+decoder :: Message a => Compression -> Decoder (Either String a)
+decoder compression = runGetIncremental $ do
+    isCompressed <- getInt8      -- 1byte
+    let decompress = if isCompressed == 0 then id else (_decompressionFunction compression)
+    n <- getWord32be             -- 4bytes
+    decodeMessage . decompress <$> getByteString (fromIntegral n)
+
+-- | Tries finalizing a Decoder.
+fromDecoder :: Decoder (Either String a) -> Either String a
+fromDecoder (Fail _ _ msg) = Left msg
+fromDecoder (Partial _)    = Left "got only a subet of the message"
+fromDecoder (Done _ _ val) = val
+
+decodeOutput
+  :: (Service s, HasMethod s m)
+  => RPC s m
+  -> Compression
+  -> Decoder (Either String (MethodOutput s m))
+decodeOutput _ = decoder
+
+decodeInput
+  :: (Service s, HasMethod s m)
+  => RPC s m
+  -> Compression
+  -> Decoder (Either String (MethodInput s m))
+decodeInput _ = decoder
+
+-- | Encodes as binary using gRPC/HTTP2 framing.
+encode :: Message m => Compression -> m -> Builder
+encode compression plain =
+    mconcat [ singleton (if _compressionByteSet compression then 1 else 0)
+            , putWord32be (fromIntegral $ ByteString.length bin)
+            , fromByteString (_compressionFunction compression $ bin)
+            ]
+  where
+    bin = encodeMessage plain
+
+-- | Finalizes a Builder.
+fromBuilder :: Builder -> ByteString
+fromBuilder = toStrict . toLazyByteString
+
+encodeInput
+  :: (Service s, HasMethod s m)
+  => RPC s m
+  -> Compression
+  -> MethodInput s m -> Builder
+encodeInput _ = encode
+
+encodeOutput
+  :: (Service s, HasMethod s m)
+  => RPC s m
+  -> Compression
+  -> MethodOutput s m -> Builder
+encodeOutput _ = encode
+
+-- | Opaque type for handling compression.
+--
+-- So far, only "pure" compression algorithms are supported.
+-- TODO: suport IO-based compression implementations once we move from 'Builder'.
+data Compression = Compression {
+    _compressionName       :: ByteString
+  , _compressionByteSet    :: Bool
+  , _compressionFunction   :: (ByteString -> ByteString)
+  , _decompressionFunction :: (ByteString -> ByteString)
+  }
+
+grpcCompressionHV :: Compression -> HeaderValue
+grpcCompressionHV = _compressionName
+
+-- | Do not compress.
+uncompressed :: Compression
+uncompressed = Compression "identity" False id id
+
+-- | Use gzip as compression.
+gzip :: Compression
+gzip = Compression "gzip" True (toStrict . GZip.compress . fromStrict) (toStrict . GZip.decompress . fromStrict)
diff --git a/src/Network/GRPC/HTTP2/Types.hs b/src/Network/GRPC/HTTP2/Types.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/GRPC/HTTP2/Types.hs
@@ -0,0 +1,146 @@
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE KindSignatures #-}
+{-# LANGUAGE LambdaCase #-}
+{-# LANGUAGE OverloadedStrings #-}
+
+-- | Module for GRPC <> HTTP2 mapping.
+module Network.GRPC.HTTP2.Types where
+
+import           Control.Exception (Exception)
+import           Data.ProtoLens.Service.Types (Service(..), HasMethod, HasMethodImpl(..))
+import           Data.Proxy (Proxy(..))
+import           Data.ByteString.Char8 (ByteString)
+import qualified Data.ByteString.Char8 as ByteString
+import           GHC.TypeLits (Symbol, symbolVal)
+
+-- | HTTP2 Header Key.
+type HeaderKey = ByteString
+
+-- | HTTP2 Header Value.
+type HeaderValue = ByteString
+
+grpcTimeoutH :: HeaderKey
+grpcTimeoutH = "grpc-timeout"
+
+grpcEncodingH :: HeaderKey
+grpcEncodingH = "grpc-encoding"
+
+grpcAcceptEncodingH :: HeaderKey
+grpcAcceptEncodingH = "grpc-accept-encoding"
+
+grpcAcceptEncodingHVdefault :: HeaderValue
+grpcAcceptEncodingHVdefault = "identity,gzip"
+
+grpcStatusH :: HeaderKey
+grpcStatusH = "grpc-status"
+
+grpcMessageH :: HeaderKey
+grpcMessageH = "grpc-message"
+
+grpcContentTypeHV :: HeaderValue
+grpcContentTypeHV = "application/grpc+proto"
+
+grpcStatusHV :: HeaderValue
+grpcStatusHV = "Grpc-Status"
+
+grpcMessageHV :: HeaderValue
+grpcMessageHV = "Grpc-Message"
+
+-- https://grpc.io/grpc/core/impl_2codegen_2status_8h.html#a35ab2a68917eb836de84cb23253108eb
+data GRPCStatusCode =
+    OK
+  | CANCELLED
+  | UNKNOWN
+  | INVALID_ARGUMENT
+  | DEADLINE_EXCEEDED
+  | NOT_FOUND
+  | ALREADY_EXISTS
+  | PERMISSION_DENIED
+  | UNAUTHENTICATED
+  | RESOURCE_EXHAUSTED
+  | FAILED_PRECONDITION
+  | ABORTED
+  | OUT_OF_RANGE
+  | UNIMPLEMENTED
+  | INTERNAL
+  | UNAVAILABLE
+  | DATA_LOSS
+  deriving (Show, Eq, Ord)
+
+trailerForStatusCode :: GRPCStatusCode -> ByteString
+trailerForStatusCode = \case
+    OK
+      -> "0"
+    CANCELLED
+      -> "1"
+    UNKNOWN
+      -> "2"
+    INVALID_ARGUMENT
+      -> "3"
+    DEADLINE_EXCEEDED
+      -> "4"
+    NOT_FOUND
+      -> "5"
+    ALREADY_EXISTS
+      -> "6"
+    PERMISSION_DENIED
+      -> "7"
+    UNAUTHENTICATED
+      -> "16"
+    RESOURCE_EXHAUSTED
+      -> "8"
+    FAILED_PRECONDITION
+      -> "9"
+    ABORTED
+      -> "10"
+    OUT_OF_RANGE
+      -> "11"
+    UNIMPLEMENTED
+      -> "12"
+    INTERNAL
+      -> "13"
+    UNAVAILABLE
+      -> "14"
+    DATA_LOSS
+      -> "15"
+
+type GRPCStatusMessage = ByteString
+
+data GRPCStatus = GRPCStatus !GRPCStatusCode !GRPCStatusMessage
+  deriving (Show, Eq, Ord)
+
+instance Exception GRPCStatus
+
+trailers :: GRPCStatus -> [(ByteString, ByteString)]
+trailers (GRPCStatus s msg) =
+    if ByteString.null msg then [status] else [status, message]
+  where
+    status = ("grpc-status", trailerForStatusCode s)
+    message = ("grpc-message", msg)
+
+-- | A proxy type for giving static information about RPCs.
+data RPC (s :: *) (m :: Symbol) = RPC
+
+-- | Returns the HTTP2 :path for a given RPC.
+path :: (Service s, HasMethod s m) => RPC s m -> ByteString
+{-# INLINE path #-}
+path rpc = "/" <> pkg rpc Proxy <> "." <> srv rpc Proxy <> "/" <> meth rpc Proxy
+  where
+    pkg :: (Service s) => RPC s m -> Proxy (ServicePackage s) -> ByteString
+    pkg _ p = ByteString.pack $ symbolVal p
+
+    srv :: (Service s) => RPC s m -> Proxy (ServiceName s) -> ByteString
+    srv _ p = ByteString.pack $ symbolVal p
+
+    meth :: (Service s, HasMethod s m) => RPC s m -> Proxy (MethodName s m) -> ByteString
+    meth _ p = ByteString.pack $ symbolVal p
+
+-- | Timeout in seconds.
+newtype Timeout = Timeout Int
+
+showTimeout :: Timeout -> ByteString
+showTimeout (Timeout n) = ByteString.pack $ show n ++ "S"
+
+-- | The HTTP2-Authority portion of an URL (e.g., "dicioccio.fr:7777").
+type Authority = ByteString.ByteString
+
