Laravel’s Context feature lets you record and share information across the lifecycle of a request, queued job, or console command. Any data you add through the Illuminate\Support\Facades\Context facade is automatically appended as metadata to every log entry your application writes.This keeps shared information — such as a trace ID — clearly separated from data passed to individual log calls. Context is especially useful for distributed systems where you need to trace a single request through multiple layers, including queued jobs.
scope temporarily modifies the context for the duration of a closure, then restores it to its original state automatically. Use it when you need extra information in your logs for a single isolated operation without affecting the rest of the request.
use Illuminate\Support\Facades\Context;use Illuminate\Support\Facades\Log;Context::add('trace_id', 'abc-999');Context::addHidden('user_id', 123);Context::scope( function () { Context::add('action', 'adding_friend'); $userId = Context::getHidden('user_id'); Log::debug("Adding user [{$userId}] to friends list."); // Adding user [987] to friends list. {"trace_id":"abc-999","user_name":"taylor_otwell","action":"adding_friend"} }, data: ['user_name' => 'taylor_otwell'], hidden: ['user_id' => 987],);// After the scope, original values are restoredContext::all();// ['trace_id' => 'abc-999']Context::allHidden();// ['user_id' => 123]
If you mutate an object stored in the context inside a scoped closure, that mutation persists outside the scope. Primitive values are safely restored.
Store data that should never appear in log output using the hidden context. Hidden values are only accessible through the dedicated *Hidden methods and are not written to logs.
use Illuminate\Support\Facades\Context;Context::addHidden('key', 'value');Context::getHidden('key');// 'value'Context::get('key');// null — not accessible through regular get
When you dispatch a job to the queue, the current context is automatically serialized and stored with the job payload. When the job runs, the context is restored so any trace_id or other values from the original request are available throughout job execution.
// Set in middlewareContext::add('trace_id', Str::uuid()->toString());// Dispatched in a controllerProcessPodcast::dispatch($podcast);
class ProcessPodcast implements ShouldQueue{ use Queueable; public function handle(): void { Log::info('Processing podcast.', ['podcast_id' => $this->podcast->id]); }}
Context::dehydrating registers a closure that runs just before a job is serialized. Use it to capture runtime configuration values that should travel with the job.
Inside a dehydrating callback, use only the $context repository argument — never the Context facade. Using the facade modifies the current process’s context, not the job payload.
Context::hydrated registers a closure that runs after the context is restored on the queue worker. Use it to apply the restored values back to your application’s configuration.
// AppServiceProvider.phpuse Illuminate\Log\Context\Repository;use Illuminate\Support\Facades\Config;use Illuminate\Support\Facades\Context;public function boot(): void{ Context::hydrated(function (Repository $context) { if ($context->hasHidden('locale')) { Config::set('app.locale', $context->getHidden('locale')); } });}
Inside a hydrated callback, use only the $context repository argument — never the Context facade.