How to treat json data from Postgres as a string in Ecto?

I have a json field in postgres, but I’d like encoding/decoding to only happen on the client, so the data should just be treated as a string on the server. I’ve tried doing that with the following custom type:

defmodule Backend.Model.Types.VerbatimJson do
  @moduledoc """
  Stores a value in the db as json, but returns it as binary.
  Used for data where we don't need to deserialize it into a map on the server.
  @behaviour Ecto.Type
  def type, do: :string

  # cast is called before dump. in our case we only expect binary strings.
  def cast(json_blob) when is_binary(json_blob) do
    {:ok, json_blob}

  def cast(_), do: :error

  # load is called when fetching stuff *from* the database
  def load(json_blob) when is_binary(json_blob) do

  # dump is called when ecto is saving stuff *to* the database.
  def dump(json_blob) when is_binary(json_blob) do
    {:ok, json_blob}

  def dump(_), do: :error

The problem is that when using this type in a schema, and trying to save a value, it stores the whole value as a string, defeating the whole point of using the json value type. The only way I’ve gotten it to work is by returning a map from dump, but I’d like to avoid the whole string -> map conversion altogether and just treat the json string I’m passing as a literal json value.

(How) can I do that?

Do you actually make queries that involve the JSON? If not, it feels as if storing it as string in the Database should just work…


How did you make the table’s column? Show us the migration. Also, how did you declare the field in your Ecto schema?

We currently don’t make any queries for it, but given the minuscule overhead of validating the json, it’s nice to have the possibility there.

here’s the schema:

schema "theme_files" do
    field(:files, :string, default: <<"{}">>)
    belongs_to(:apps, Backend.Model.App, foreign_key: :app_pk, references: :pk)


defmodule Backend.Repo.Migrations.AddNotificationsTable do
  use Ecto.Migration

  def change do
    create_if_not_exists table(:theme_files, primary_key: false) do
      add :pk, :uuid, primary_key: true
      add :app_pk, references(:apps, column: :pk, type: :uuid)
      add :files, :json