Skip to content

boxxxie/superjson

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

10 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

SuperJSON for Elixir

Hex.pm Documentation License: MIT

A high-fidelity SuperJSON decoder and encoder for Elixir. This is a complete Elixir port of the original TypeScript SuperJSON library.

Seamlessly serialize and rehydrate JavaScript/TypeScript complex types (Dates, MapSets, Maps, BigInts, Regexps, URLs, Errors, and referential equalities) into native Elixir data structures.

Perfect for communicating with JS/TS frameworks that use SuperJSON for payload serialization, such as Trigger.dev, tRPC, Remix, Blitz.js, or Next.js.

Installation

Add superjson to your list of dependencies in mix.exs:

def deps do
  [
    {:superjson, "~> 0.1.0"}
  ]
end

Features

  • Bidirectional: Full support for both decoding (JS -> Elixir) and encoding (Elixir -> JS).
  • DateTime / Date: Converts ISO8601 string fields back to %DateTime{} and vice-versa.
  • BigInt Support: Parses stringified BigInts into native Elixir integers, and encodes large Elixir integers as bigint.
  • RegExp Support: Converts JavaScript regex strings (/pattern/flags) into native %Regex{} structs.
  • Sets and Maps: Rehydrates JavaScript Set into MapSet and JavaScript Map into standard Elixir Map. Nested value annotations are rigorously supported!
  • URLs & Errors: Maps JS URL objects to %URI{}, and JS Error objects to %RuntimeError{}.
  • Special Numbers: Gracefully handles JS NaN, Infinity, and -Infinity by mapping them to Elixir atoms (:nan, :inf, :"-inf").
  • Referential Equalities: Resolves structural references and shared object identity paths on decoding to perfectly restore graph structures.
  • Path Escaping: Implements the official SuperJSON path stringification and parsing specifications (handling escaped dots \\. and backslashes \\\\).

Usage

Decoding (JS -> Elixir)

Usually, you will receive a raw SuperJSON string from an API or webhook. You can decode it directly into native Elixir structs: (See test/super_json/readme_test.exs:L6-L29 for the validation of this example)

json_string = """
{
  "json": {
    "createdAt": "2023-10-10T15:20:00Z",
    "amount": "9007199254740991",
    "pattern": "/abc/i"
  },
  "meta": {
    "values": {
      "createdAt": ["Date"],
      "amount": ["bigint"],
      "pattern": ["regexp"]
    }
  }
}
"""

{:ok, result} = SuperJSON.decode(json_string)
# Or raise on error:
# result = SuperJSON.decode!(json_string)

# result["createdAt"] => ~U[2023-10-10 15:20:00Z]
# result["amount"]    => 9007199254740991
# result["pattern"]   => ~r/abc/i

If your HTTP client (like Req or HTTPoison) automatically parses JSON responses into Elixir maps using Jason, you can simply pass that pre-parsed map directly to SuperJSON:

# Assume `response.body` was already parsed by your HTTP client:
# response.body = %{"json" => ..., "meta" => ...}

{:ok, result} = SuperJSON.decode(response.body)

Encoding (Elixir -> JS)

Pass native Elixir structs, MapSets, and atoms, and get a SuperJSON payload ready to be sent to a JavaScript client. (See test/super_json/readme_test.exs:L31-L55 for the validation of this example)

my_data = %{
  "date" => ~U[2026-01-01 12:00:00Z],
  "set" => MapSet.new([1, 2, :nan]),
  "url" => URI.parse("https://www.example.com")
}

encoded = SuperJSON.encode(my_data)
# %{
#   "json" => %{
#     "date" => "2026-01-01T12:00:00Z",
#     "set" => [1, 2, "NaN"],
#     "url" => "https://www.example.com"
#   },
#   "meta" => %{
#     "values" => %{
#       "date" => ["Date"],
#       "set" => ["set", %{"2" => ["number"]}],
#       "url" => ["URL"]
#     }
#   }
# }

# You can also use `SuperJSON.encode!/1` to return a raw JSON string directly:
# json_string = SuperJSON.encode!(my_data)

License

This package is licensed under the MIT License.

About

SuperJSON Elixir Library

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages