What is JSON to Haskell Data Type Generator?
Haskell data types with record syntax provide named fields with type annotations, and the deriving clause automatically generates Show and Eq instances for debugging and comparison. This generator transforms your JSON data into idiomatic Haskell data declarations with automatic type inference — strings become String, integers become Int, floats become Double, booleans become Bool, and null values become Maybe a for optional fields. Field names are prefixed with the type name to avoid Haskell's global record namespace collisions, following the convention used in production Haskell codebases.
How to Use
- Paste your JSON object into the input area — the tool requires a JSON object, not an array or primitive
- Click "Generate" to produce Haskell data type definitions with record syntax
- Review the generated code: nested objects appear as separate data types before the root type
- Copy the output into your Haskell project — typically in a Types.hs or Domain.hs module
- Add Aeson FromJSON/ToJSON instances for JSON serialization using either Generic deriving or manual instances
Why Use This Tool?
Tips & Best Practices
- Provide realistic sample data because type inference is driven by actual JSON values — a float like 3.0 produces Double, not Int
- Field names are prefixed with the type name (e.g., userId, userName for User) to avoid Haskell's global record namespace collisions
- Null values are typed as Maybe a — consider replacing with a concrete type like Maybe String or Maybe Int in production
- Empty arrays are typed as [a] — you should specialize this to a concrete type like [String] or [Int]
- For JSON serialization, derive Generic and use deriveJSON from Aeson or write manual FromJSON/ToJSON instances
Frequently Asked Questions
How are JSON types mapped to Haskell types?
JSON strings become String, integers become Int, floats become Double, booleans become Bool, null becomes Maybe a (a generic Maybe), empty arrays become [a], and non-empty arrays become [T] where T is inferred from the first element. Nested objects generate separate data types with their own field definitions.
Why are field names prefixed with the type name?
Haskell record fields share a global namespace — two different data types cannot have fields with the same name. To avoid compilation errors, each field is prefixed with the type name (e.g., userId and userName for the User data type, orderId and orderName for the Order data type). This is standard practice in production Haskell codebases.
When should I NOT use generated Haskell data types for JSON?
Avoid generated data types when your JSON has highly dynamic or unpredictable fields, since Haskell data types require a fixed set of fields at compile time. For APIs with varying response shapes, consider using Aeson's Value type with lens-based access, or the aeson-casing package for automatic field name conversion. Also, for very large JSON structures, Generic-based deriving may be slow to compile.
How are nested objects handled?
Each nested JSON object becomes its own Haskell data type with a PascalCase name derived from the field name. Types are ordered children-first so that referenced types are defined before the types that use them, satisfying Haskell's sequential type declaration requirements.
What deriving clauses are added and can I add more?
All generated data types derive Show and Eq instances, which are the most commonly needed for debugging and comparison. You can manually add derivings for Ord, Generic, FromJSON, ToJSON, or any other type class. If you use Aeson's Generic deriving, add deriving (Generic) and use deriveJSON to generate FromJSON and ToJSON instances.
Is my JSON data sent to a server?
No. All code generation happens entirely in your browser using client-side JavaScript. Your JSON data never leaves your device, so you can safely convert sensitive API responses or proprietary data structures.
Real-world Examples
API Response Data Types with Aeson
Generate Haskell data types from a REST API response for type-safe JSON parsing with Aeson.
{"id": 1, "name": "Alice", "email": "[email protected]", "is_active": true, "address": {"street": "123 Main St", "city": "Springfield"}}data Address = Address
{ addressStreet :: String
, addressCity :: String
} deriving (Show, Eq)
data User = User
{ userId :: Int
, userName :: String
, userEmail :: String
, userIsActive :: Bool
, userAddress :: Address
} deriving (Show, Eq)Optional Fields with Maybe
Model a JSON payload where some fields may be null, using Haskell Maybe types for safe access.
{"title": "Draft", "score": null, "tags": ["review"]}data Root = Root
{ rootTitle :: String
, rootScore :: Maybe a
, rootTags :: [String]
} deriving (Show, Eq)