Count Tasks By Department - Laravel Query Builder

use count() simple way close to your code:

foreach($departments as $department){
    $tasks = DB::table('tasks')
    ->join('users', 'users.id', '=' , 'tasks.user_id')
    ->where('users.department_id', $department->id),
    ->where('tasks.completed_at', '!=', null)
    ->count();
    // echo "$department->id : $tasks";
}

You can select raw a count like this

...
->select(DB::raw('count(tasks.id) as task_count'))
...

Don't forget that count is a non aggregate function so you can disable it in your database variables OR add at the end a groupBy method

...
->groupBy('departments.id')

This is my version of your code:

$departments = DB::table('tasks')
            ->join('users', 'users.id', '=' , 'tasks.user_id')
            ->join('departments', 'departments.id', '=', 'users.department_id')
            ->where([
                ['departments.id', '=', $department->id],
                ['tasks.completed_at', '!=', null]
            ])
            ->select('departments.id')
            ->select(DB::raw('count(tasks.id) as task_count'))
            ->groupBy('departments.id')
            ->get();

foreach($departments as $department) {
    //$department->task_count
    //$department->id
}

Don't Forget to add the DB Facade

use Illuminate\Support\Facades\DB;

OR if your eloquent is properly configured you can use it instead of the query builder above:

//$user = User::find(1);

foreach($user->departments as $department) {
    $task_count = $department
        ->tasks
        ->map(fn($task) $task->completed_at != null)
        ->count();
}