Saltar al contenido

Imagina que necesitas registrar logs, enviar métricas o limpiar archivos temporales después de procesar una petición. Normalmente esto retrasa la respuesta al usuario. Con defer() ejecutas ese código después de enviar el response.

Compatibilidad

  • Laravel: 11+

  • PHP: 8.2+

¿Qué hace defer()?

defer() registra un callback que se ejecutará una vez que la respuesta HTTP haya sido enviada al cliente. El usuario recibe su respuesta inmediatamente, y el código diferido se ejecuta después.

<?php

use function Illuminate\Support\defer;

Route::post('/pedidos', function (Request $request) {
    $order = Order::create($request->validated());
    
    // Esto se ejecuta DESPUÉS de enviar la respuesta
    defer(fn () => Metrics::track('order_created', $order->id));
    
    return response()->json($order); // El usuario recibe esto inmediatamente
});

Casos de uso ideales

Logging y métricas

<?php

use function Illuminate\Support\defer;

class PaymentController extends Controller
{
    public function store(PaymentRequest $request): JsonResponse
    {
        $payment = $this->paymentService->process($request->validated());
        
        defer(function () use ($payment) {
            Log::channel('payments')->info('Pago procesado', [
                'payment_id' => $payment->id,
                'amount' => $payment->amount,
            ]);
            
            Metrics::increment('payments.processed');
        });
        
        return response()->json(['status' => 'success']);
    }
}

Limpieza de archivos temporales

<?php

use function Illuminate\Support\defer;

class ExportController extends Controller
{
    public function download(string $reportId): BinaryFileResponse
    {
        $tempPath = $this->generateReport($reportId);
        
        // Eliminar archivo después de enviarlo
        defer(fn () => Storage::delete($tempPath));
        
        return response()->download(storage_path($tempPath));
    }
}

Sincronización con servicios externos

<?php

use function Illuminate\Support\defer;

class ProductController extends Controller
{
    public function update(Product $product, ProductRequest $request): JsonResponse
    {
        $product->update($request->validated());
        
        // Sincronizar con CRM sin bloquear al usuario
        defer(fn () => CrmService::sync($product));
        
        return response()->json($product);
    }
}

Cache warming

<?php

use function Illuminate\Support\defer;

class CategoryController extends Controller
{
    public function store(CategoryRequest $request): JsonResponse
    {
        $category = Category::create($request->validated());
        
        // Precalentar caché de categorías
        defer(fn () => Cache::forget('categories.tree'));
        defer(fn () => app(CategoryService::class)->warmCache());
        
        return response()->json($category, 201);
    }
}

Múltiples defers

Puedes registrar varios defer(). Se ejecutan en orden FIFO (primero en entrar, primero en salir):

<?php

use function Illuminate\Support\defer;

defer(fn () => logger('Primero'));
defer(fn () => logger('Segundo'));
defer(fn () => logger('Tercero'));

// Log: Primero, Segundo, Tercero

Cancelar un defer

Puedes nombrar un defer y cancelarlo antes de que se ejecute:

<?php

use function Illuminate\Support\defer;

defer(fn () => Metrics::track('page_view'), 'tracking');

if ($user->hasOptedOut()) {
    defer()->forget('tracking');
}

defer() vs Queues

Aspecto

defer()

Queues

Ejecución

Mismo proceso, después del response

Proceso separado (worker)

Infraestructura

Ninguna

Redis, database, etc.

Reintentos

No

Tareas largas

No recomendado

Ideal

Latencia

Milisegundos

Depende del worker

Usa defer() para:

  • Tareas rápidas (< 1 segundo)

  • Logging y métricas

  • Limpieza menor

  • Cuando no necesitas reintentos

Usa Queues para:

  • Envío de emails

  • Procesamiento de imágenes

  • Llamadas API lentas

  • Cualquier cosa que pueda fallar y necesite reintento

Consideraciones importantes

No uses defer para tareas críticas

Si el servidor muere antes de ejecutar el defer, el código se pierde:

<?php

// ❌ Malo: si falla, pierdes el pago
defer(fn () => $this->confirmPayment($order));

// ✅ Bueno: usa queue para tareas críticas
ConfirmPaymentJob::dispatch($order);

Acceso a variables

Los closures capturan variables por valor. Cuidado con objetos que pueden cambiar:

<?php

use function Illuminate\Support\defer;

$user = User::find(1);

defer(function () use ($user) {
    // $user tiene los datos del momento en que se registró el defer
    Log::info($user->name);
});

$user->name = 'Nuevo nombre'; // Esto NO afecta al defer

Conclusión

defer() es perfecto para esas pequeñas tareas que no quieres que afecten el tiempo de respuesta pero que tampoco justifican la complejidad de una cola. Logging, métricas, limpieza... todo eso puede ir después del response.

school Curso completo

Curso Laravel 12
Completo 2026

El único curso 100% actualizado que incluye Laravel 12, Livewire 3, Vue 3, React 19 e Inertia 2. Aprende con proyectos reales y las últimas funcionalidades.

access_time 8 horas de contenido
layers 4 tecnologías en 1
update 100% actualizado
code Proyectos prácticos
Ver Curso Laravel 12 arrow_forward

star Incluido en cualquier suscripción

Rutas de aprendizaje