avro: Avro serialization support for Haskell

[ bsd3, data, library ] [ Propose Tags ]
Versions [RSS],,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, (info)
Change log ChangeLog.md
Dependencies aeson, array, base (>=4 && <5), base16-bytestring, bifunctors, binary, bytestring, containers, data-binary-ieee754, deepseq, fail, hashable, mtl, scientific, semigroups, tagged, template-haskell (>=2.4), text (>=1.2.3 && <1.3), tf-random, unordered-containers, vector, zlib [details]
License BSD-3-Clause
Author Thomas M. DuBuisson
Maintainer Alexey Raga <alexey.raga@gmail.com>
Category Data
Home page https://github.com/haskell-works/avro#readme
Bug tracker https://github.com/haskell-works/avro/issues
Source repo head: git clone https://github.com/haskell-works/avro
Uploaded by haskellworks at 2019-10-03T22:31:22Z
Distributions LTSHaskell:
Reverse Dependencies 11 direct, 1 indirect [details]
Downloads 29635 total (124 in the last 30 days)
Rating 2.25 (votes: 2) [estimated by Bayesian average]
Your Rating
  • λ
  • λ
  • λ
Status Docs available [build log]
Last success reported on 2019-10-03 [all 1 reports]

Readme for avro-

[back to package description]

Native Haskell implementation of Avro

This is a Haskell Avro library useful for decoding and encoding Avro data structures. Avro can be thought of as a serialization format and RPC specification which induces three separable tasks:

  • Serialization/Deserialization - This library has been used "in anger" for:
    • Deserialization of avro container files
    • Serialization/deserialization Avro messages to/from Kafka topics
  • RPC - There is currently no support for Avro RPC in this library.

This library also provides functionality for automatically generating Avro-related data types and instances from Avro schemas (using TemplateHaskell).


This library provides the following conversions between Haskell types and Avro types:

Haskell type Avro type
() "null"
Bool "boolean"
Int, Int64 "long"
Int32 "int"
Double "double"
Text "string"
ByteString "bytes"
Maybe a ["null", "a"]
Either a b ["a", "b"]
Map Text a {"type": "map", "value": "a"}
Map String a {"type": "map", "value": "a"}
HashMap Text a {"type": "map", "value": "a"}
HashMap String a {"type": "map", "value": "a"}
[a] {"type": "array", "value": "a"}

User defined data types should provide HasAvroSchema/ToAvro/FromAvro instances to be encoded/decoded to/from Avro.

Defining types and HasAvroSchema / FromAvro / ToAvro manually

Typically these imports are useful:

import           Data.Avro
import           Data.Avro.Schema as S
import qualified Data.Avro.Types  as AT

Assuming there is a data type to be encoded/decoded from/to Avro:

data Gender = Male | Female deriving (Eq, Ord, Show, Enum)
data Person = Person
     { fullName :: Text
     , age      :: Int32
     , gender   :: Gender
     , ssn      :: Maybe Text
     } deriving (Show, Eq)

Avro schema for this type can be defined as:

genderSchema :: Schema
genderSchema = mkEnum "Gender" [] Nothing Nothing ["Male", "Female"]

personSchema :: Schema
personSchema =
  Record "Person" Nothing [] Nothing Nothing
    [ fld "name"   String       Nothing
    , fld "age"    Int          Nothing
    , fld "gender" genderSchema Nothing
    , fld "ssn" (mkUnion $ Null :| [String]) Nothing
     fld nm ty def = Field nm [] Nothing Nothing ty def

instance HasAvroSchema Person where
  schema = pure personSchema

ToAvro instance for Person can be defined as:

instance ToAvro Person where
  schema = pure personSchema
  toAvro p = record personSchema
             [ "name"   .= fullName p
             , "age"    .= age p
             , "gender" .= gender p
             , "ssn"    .= ssn p

FromAvro instance for Person can be defined as:

instance FromAvro Person where
  fromAvro (AT.Record _ r) =
    Person <$> r .: "name"
           <*> r .: "age"
           <*> r .: "gender"
           <*> r .: "ssn"
  fromAvro r = badValue r "Person"

Defining types and HasAvroSchema / FromAvro / ToAvro "automatically"

This library provides functionality to derive Haskell data types and HasAvroSchema/FromAvro/ToAvro instances "automatically" from already existing Avro schemas (using TemplateHaskell).


deriveAvro will derive data types, FromAvro and ToAvro instances from a provided Avro schema file:

{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE DeriveGeneric   #-}
import Data.Avro.Deriving

deriveAvro "schemas/contract.avsc"

Similarly, deriveFromAvro can be used to only derive data types and FromAvro, but not ToAvro instances.

If you prefer defining Avro schema in Haskell and not in avsc, then deriveAvro' can be used instead of deriveAvro.


When Haskell data types are generated, these conventions are followed:

  • Type and field names are "sanitized": all the charachers except [a-z,A-Z,',_] are removed from names
  • Field names are prefixed with the name of the record they are declared in.

For example, if Avro schema defines Person record as:

{ "type": "record",
  "name": "Person",
  "fields": [
    { "name": "name", "type": "string"}

then generated Haskell type will look like:

data Person = Person
     { personName :: Text
     } deriving (Show, Eq)


Two-parts unions like ["null", "MyType"] or ["MyType", "YourType"] are supported (as Haskell's Maybe MyType and Either MyType YourType), but multi-parts unions are currently not supported. It is not due to any fundamental problems but because it has not been done yet. PRs are welcomed! :)


Please see the TODO