JSON (JavaScript Object Notation) has become the universal standard for data exchange in modern web applications. Its lightweight, human-readable format makes it ideal for APIs, configuration files, and handling unstructured data in databases.
In Laravel applications, we often encounter scenarios where:
- We need to store large datasets without creating numerous database columns
- The data structure is dynamic or unpredictable
- We want to maintain complex nested relationships in a single field
This tutorial will walk you through storing and retrieving JSON data in a Laravel 12 application with proper type casting and database optimization.
Setting Up the Project
Step 1: Install Laravel 12
Begin by creating a new Laravel project:
composer create-project laravel/laravel json-storage-app
cd json-storage-app
Step 2: Create Migration with JSON Column
Generate a migration for our sample “items” table:
php artisan make:migration create_items_table
Define the table structure with a JSON column:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('items', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->json('data')->nullable(); // JSON column for our unstructured data
$table->timestamps();
});
}
public function down(): void
{
Schema::dropIfExists('items');
}
};
Run the migration:
php artisan migrate
Creating the Model with JSON Casting
Step 3: Generate and Configure the Model
Create the Item model:
php artisan make:model Item
Implement proper JSON casting:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Casts\Attribute;
class Item extends Model
{
use HasFactory;
protected $fillable = [
'title',
'data' // Allow mass assignment for these fields
];
protected function data(): Attribute
{
return Attribute::make(
get: fn ($value) => json_decode($value, true), // Convert JSON to array when retrieving
set: fn ($value) => json_encode($value), // Convert array to JSON when storing
)->shouldCache();
}
}
Implementing the Controller Logic
Step 4: Set Up the Route
Define a test route in routes/web.php:
<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\ItemController;
Route::get('items', [ItemController::class, 'storeAndRetrieve']);
Step 5: Create the Controller
Generate and configure the controller:
php artisan make:controller ItemController
Add the demonstration logic:
<?php
namespace App\Http\Controllers;
use App\Models\Item;
class ItemController extends Controller
{
public function storeAndRetrieve()
{
// Sample data structure
$itemData = [
'title' => 'Sample Item',
'data' => [
'metadata' => [
'author' => 'John Doe',
'version' => 1.2
],
'tags' => ['laravel', 'json', 'storage'],
'settings' => [
'notifications' => true,
'retry_count' => 3
]
]
];
// Store the item
$item = Item::create($itemData);
// Retrieve and display the JSON data
return response()->json([
'stored_data' => $item->data,
'specific_value' => $item->data['metadata']['author']
]);
}
}
Testing the Implementation
Run the development server:
php artisan serve
Visit the test endpoint:
http://localhost:8000/items
You should see output similar to:
{
"stored_data": {
"metadata": {
"author": "John Doe",
"version": 1.2
},
"tags": ["laravel", "json", "storage"],
"settings": {
"notifications": true,
"retry_count": 3
}
},
"specific_value": "John Doe"
}
Best Practices for JSON Storage in Laravel
- Schema Design: Use JSON columns for truly dynamic data, not as a replacement for proper relational design
- Indexing: Consider adding generated columns for fields you’ll search frequently
- Validation: Always validate JSON data before storage
- Querying: Use Laravel’s JSON query operators for efficient searching
- Documentation: Clearly document your JSON structure for future maintainability
This implementation provides a solid foundation for working with JSON data in Laravel 12, combining the flexibility of NoSQL concepts with the power of Eloquent ORM.