JSON vs JSONB columns in Laravel

I once wanted to dig a little deeper into JSON column types, to see if they were a fit for the design I had in mind. The best way to get more experience with them is, well, toying around with them! So I spun up a fresh Laravel installation and created a `Test` model with a migration. When writing up the migration for this model, my editor autocompleted that there was not only a JSON column, but also a JSONb column.

Curious as I am, I looked up the documentation for the JSONb column to find what the differences are. The Laravel 9 documentation does not provide any thorough documentation as to why you would want to use the JSONb column type though. So I set out to the internet to find what this mysterious JSONb column was.

Postgres

My first hits on the web were all related to PostgreSQL. As the PostgreSQL documentation defines it:

The JSON and JSONb data types accept almost identical sets of values as input. The major practical difference is one of efficiency. The JSON data type stores an exact copy of the input text, which processing functions must reparse on each execution; while JSONb data is stored in a decomposed binary format that makes it slightly slower to input due to added conversion overhead, but significantly faster to process, since no reparsing is needed. JSONb also supports indexing, which can be a significant advantage.

So, basically this boils down to: JSONb offers faster reads at the cost of a slower write.

Use case

Since basically all  my projects use the MySQL database, the PostgreSQL specific implementation of the JSONb column is not all that relevant. So, how does this all work in MySQL?

First off, MySQL does not offer JSONb columns at all. Then how does Laravel handle this?

In vendor/laravel/framework/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php:703

/**
* Create the column definition for a jsonb type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeJsonb(Fluent $column)
{
    return 'json';
}

We see that in the MySqlGrammar the JSONb column is mapped to a regular JSON column!
But, What does that mean for our nice read performance gain?
Well, as it seems, MySQL offers alike functionality to the JSONb column on the JSON column by default.

From the MySQL documentation:

JSON documents stored in JSON columns are converted to an internal format that permits quick read access to document elements. When the server later must read a JSON value stored in this binary format, the value need not be parsed from a text representation. The binary format is structured to enable the server to look up subobjects or nested values directly by key or array index without reading all values before or after them in the document.

So the MySQL implementation uses the binary structured format to improve read performance too.

Conclusion

It appears that because no native JSONb column exists in MySQL, the JSON column is used by default. Although this may sound weird, the MySQL implementation of the JSON column offers functionality that is very alike to the way the JSONb column is used in PostgreSQL by default, namely the internal binary storage of the JSON document. So, it would (for now at least) never make sense to use the JSONb column type in a migration when using the MySQL database. Though, when using PostgreSQL, significant performance gains may be achieved in terms of reads, at the cost of slower writes.