Laravel - How to set a message on progress bar
Stefan Bogdanescu
Founder & Senior Architect · 2026-06-29
Laravel Console Commands: Mastering Progress Bars and Custom Messaging
As developers working with Laravel, we often deal with command-line interfaces (CLI) for batch processing, data migration, or long-running tasks. A crucial part of creating a good developer experience is providing clear, real-time feedback to the user. One common way to achieve this is by implementing progress bars. However, customizing these outputs—specifically adding meaningful messages alongside the progress indicator—can sometimes lead to unexpected errors if you rely on methods that aren't designed for direct string manipulation.
This post addresses a specific challenge: how to effectively set dynamic messages while running progress bars in Laravel Artisan commands, and why methods like $this->output->setMessage() might fail.
The Pitfall of Direct Output Methods
You are encountering an issue because the underlying structure of the Illuminate\Console\Output class is designed primarily for managing structured output styles and progress tracking rather than arbitrary message injection directly through simple setter methods like setMessage(). When you attempt to call methods that don't exist on the specific object instance (like $this->output), PHP throws a fatal error, indicating an undefined method.
The example you referenced, using progressStart(), progressAdvance(), and progressFinish(), is the correct mechanism for handling the progress state. To display custom text or messages during this process, we must rely on standard output functions (echo or $this->line()) to interleave our status updates with the progress bar updates.
The Solution: Interleaving Status Updates and Progress
To successfully set a message on a progress bar, you need to treat the progress tracking and the messaging as separate concerns. You use the progress methods to manage the visual bar, and you use standard output methods to print the textual status that contextualizes the progress.
Here is how you can combine these concepts effectively within an Artisan command:
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
class ProcessUsers extends Command
{
protected $signature = 'app:process-users';
protected $description = 'Processes all users with a progress bar.';
public function handle()
{
$users = \App\Models\User::all();
$total = count($users);
// 1. Start the progress bar
$this->output->progressStart($total);
$this->line("Starting user processing..."); // Custom message 1
foreach ($users as $index => $user) {
// Print the current item being processed
$this->line("Processing User ID: " . $user->id . " (" . ($index + 1) . "/" . $total . ")");
// Advance the progress bar
$this->output->progressAdvance();
}
// 3. Finish the progress bar
$this->output->progressFinish();
$this->line("User processing complete!"); // Custom message 2
}
}
Explanation of the Approach
Notice that we bypassed $this->output->setMessage() entirely. Instead, within the foreach loop, we use $this->line() to output dynamic information about the current iteration. By printing the user ID and the current position relative to the total count on each line, we achieve the desired effect of showing progress and context simultaneously. This approach is robust because it relies on the fundamental capabilities of the console output stream provided by Laravel, aligning with best practices for command-line interaction.
When developing robust tooling within the Laravel ecosystem, understanding how the framework handles input and output streams is key. As we build complex applications using Laravel, ensuring our CLI tools provide clear feedback is essential for maintainability and usability—a core principle reflected in how code should be structured across the application, much like adhering to strong architectural patterns demonstrated by Laravel itself.
Conclusion
The error you encountered stems from trying to use a method designed for styling (setFormat) where simple text output is required. For dynamic progress reporting in Laravel Artisan commands, the most effective strategy is to explicitly manage state: use progressStart(), interleave status updates with $this->line(), and finish with progressFinish(). This ensures that your command provides accurate, visible, and error-free feedback to the user while keeping the core functionality of the progress bar intact.