Building a Real-Time Task Board with Laravel, Neon, and WebSockets
Learn how to create a collaborative task management system using Laravel, Neon Postgres, and WebSockets
Real-time features can significantly improve user experience in web applications. They allow users to see updates immediately without refreshing the page. In this guide, we'll demonstrate how to add real-time functionality to a Laravel application using Neon Postgres and WebSockets.
We'll build a collaborative task board where team members can create, update, and move tasks in real-time. By the end of this guide, you'll understand how to set up WebSockets in Laravel, store and retrieve data using Neon Postgres, and broadcast updates to connected clients instantly.
Prerequisites
Before we begin, make sure you have the following:
- PHP 8.1 or higher installed on your system
- Composer for managing PHP dependencies
- A Neon account and project
Setting up the Laravel project
To get started we will need to create a new Laravel project and configuring it with Neon Postgres.
-
Create a new Laravel project:
This will create a new Laravel project in a directory named
realtime-taskboard
. And using thecd
command, we'll navigate to the project directory. -
Configure the Neon database connection. Open your
.env
file and update the database settings:Replace the placeholders with your Neon database details which you can find in the Neon console.
-
Laravel provides a few starter kits for authentication. We'll use Laravel Breeze for this project to set up authentication:
This will install Laravel Breeze, set up authentication views using Blade, run the migrations to create the necessary tables. The
npm install
andnpm run dev
commands install the frontend dependencies and compile the assets.
Now that we've set up the Laravel project and connected it to Neon Postgres, let's create the task board.
Creating the Task model and migration
Laravel uses models to interact with the database and migrations to create database tables. The task board will consist of tasks that users can create, update, and move between different statuses (e.g., 'To Do', 'In Progress', 'Done').
Let's create a model and migration for our tasks table.
-
Generate the model and migration:
This command will create a
Task
model and a migration file for thetasks
table. -
Update the migration file in
database/migrations
to create thetasks
table with the necessary columns:This migration creates a
tasks
table with columns for the tasktitle
,description
,status
, and the user who created the task. -
Run the migration:
This will create the
tasks
table in your Neon Postgres database with the specified columns and constraints in the migration file. -
Update the
Task
model inapp/Models/Task.php
:This model defines the relationship between tasks and users. Each task belongs to a user thanks to the
user()
method defined in the model. Thefillable
property specifies which attributes can be mass-assigned. Laravel then makes it easy to create, update, and retrieve tasks using theTask
model. -
One more thing that we will have to do is to update the
User
model inapp/Models/User.php
to define the relationship between users and tasks:This defines the relationship between users and tasks. Each user can have multiple tasks and can be retrieved using the
tasks()
method on theUser
model.
Setting up WebSockets
Laravel provides built-in support for broadcasting events using WebSockets. We'll use WebSockets to broadcast task creation and updates in real-time to connected clients using Pusher.
Instead of using Pusher, there are other options like Laravel WebSockets by Beyond Code, which is a self-hosted WebSockets server for Laravel applications. However, for this guide, we'll use Pusher, as it takes care of the WebSockets infrastructure for us.
With Laravel 11 to install broadcasting, you can run the following command:
Follow the prompts to set up broadcasting and when asked for reverb
, select "No" as we are going to use Pusher instead.
To set up Pusher, you need to do the following:
-
Sign up for a free account at Pusher.
-
After creating an account and a new app, update your
.env
file with your Pusher credentials:The
PUSHER_APP_ID
,PUSHER_APP_KEY
, andPUSHER_APP_SECRET
values can be found in your Pusher dashboard. ThePUSHER_APP_CLUSTER
value depends on the region where your app is hosted. For example,mt1
is for themt1
region.The
VITE_
variables are used for client-side configuration in our JavaScript code using Vite. In our case, we'll use Vite to manage our frontend assets along with Laravel Echo and Pusher. -
Install Laravel Echo and Pusher JS:
Laravel Echo is a JavaScript library that makes it easy to work with WebSockets and listen for events. Pusher JS is the JavaScript client library for Pusher that Laravel Echo uses to communicate with the Pusher service where our events are broadcasted to.
-
Open
resources/js/echo.js
and update it with your Pusher credentials:Make sure that you still have the
npm run dev
command running in the background to compile the assets and make the changes available in the browser.
Creating the task board interface
Now that we've set up the database, models, and WebSockets, let's create the task board interface where users can view, create, and update tasks.
Create a new blade file at resources/views/taskboard.blade.php
where we'll build the task board interface:
The majority of the code is HTML and JavaScript that creates the task board interface and handles task creation and updates. The real-time functionality of our task board is powered by WebSockets, implemented using Laravel Echo and Pusher. Here's a breakdown of how it works:
-
Channel Setup: We create a channel named 'taskboard' for our real-time communications:
This channel will be used for broadcasting and listening to task-related events.
-
Event Listening: We set up listeners for two types of events:
TaskCreated
: When a new task is created, we add it to the appropriate column.TaskUpdated
: When a task is updated, we remove the old task element and add the updated one.
For more information on how events are broadcasted and listened to, check out the Getting Started with Laravel Events and Listeners guide.
-
Server-Side Broadcasting: For the above to work, in our Laravel controllers, we will broadcast these events after creating or updating a task:
The
toOthers()
method ensures that the event is not sent back to the user who initiated the action. -
Real-Time Updates: When these events are received, the task board updates instantly for all connected users, providing a collaborative, real-time experience.
This WebSockets implementation allows for immediate synchronization across all clients without the need for polling or page refreshes, creating a smooth and responsive user experience.
Handling tasks
As mentioned earlier, we'll use Laravel controllers to handle task creation and updates and broadcast events to connected clients.
-
Create a controller for tasks:
-
Update
app/Http/Controllers/TaskController.php
:These methods handle task creation, retrieval, and updates. When a task is created or updated, the corresponding event is broadcast to all connected clients using the
TaskCreated
orTaskUpdated
event and thebroadcast
method. -
Create events for task creation and updates:
These commands will create two event classes in the
app/Events
directory. We'll update these classes to broadcast the task data to the 'taskboard' channel. -
Update
app/Events/TaskCreated.php
:This class defines the
TaskCreated
event, which broadcasts the newly created task to the 'taskboard' channel, allowing all connected clients to receive the update.If you need to broadcast the event to a specific user, you can use the
private
channel instead of thepublic
channel. -
Update
app/Events/TaskUpdated.php
similarly, just change the class name toTaskUpdated
: -
Update
routes/web.php
to add routes for tasks:These routes allow users to view the task board, retrieve tasks, create new tasks, and update existing tasks.
For more information on Laravel routing, check out the Laravel's Routes, Middleware, and Validation guide.
Testing the real-time task board
Now that everything is set up, let's test our real-time task board.
-
Start your Laravel development server:
This will start the Laravel development server on
http://localhost:8000
. If you already have a server running, you can skip this step. -
In another terminal, start the Laravel queue worker to process the broadcast events:
This will ensure that the broadcast events are processed and sent to connected clients.
To learn more about Laravel queues, check out the Implementing Queue Workers and Job Processing in Laravel with Neon Postgres guide.
-
Open two different browsers and visit
http://localhost:8000/taskboard
. -
Log in with two different user accounts.
-
Start creating and moving tasks in one browser. You should see the tasks appear and move in real-time in the other browser.
-
If you were to visit your Pusher dashboard, you should see the events being broadcasted.
How it works
Here's how the whole process of the real-time updates work:
-
When a user creates or updates a task, it's sent to the server.
-
The server saves the task in the Neon Postgres database.
-
After saving the task, the server broadcasts a
TaskCreated
orTaskUpdated
event using Pusher. -
Pusher sends this event to all connected users except the sender using the 'taskboard' channel.
-
The JavaScript code listening for these events receives the new or updated task and adds or moves it on the task board.
This process happens very quickly, giving the appearance of real-time updates.
Optimizing for larger applications
As your task board grows, you might need to optimize it for better performance:
-
Pagination: Instead of loading all tasks at once, implement pagination to load tasks in smaller batches. Currently, we are loading all tasks using
Task::all()
, which can be inefficient for large datasets. -
Caching: Use Laravel's caching features to cache frequently accessed data, reducing database queries.
-
Database Indexing: Add indexes to frequently queried columns in your Neon Postgres database to speed up queries. For more information, check out the Neon Postgres documentation on Indexes.
-
Queue Workers: Use multiple queue workers to process broadcast events concurrently, especially in high-traffic applications. Also, consider using Laravel Horizon for monitoring and managing your queue workers.
-
Private Channels: If you need to broadcast events to specific users or groups, use private channels to ensure data privacy. This is useful for applications with user-specific data or private conversations between users where data should not be shared with others.
Conclusion
In this guide, we've built a simple real-time collaborative task board using Laravel, Neon Postgres, and WebSockets. This example shows how you can create interactive, real-time web applications that update instantly across multiple users using Laravel's broadcasting feature.
Additional Resources
Need help?
Join our Discord Server to ask questions or see what others are doing with Neon. Users on paid plans can open a support ticket from the console. For more details, see Getting Support.