Muhammad Yasir Amin

Loading websiteโ€ฆ

More from Muhammad Yasir Amin

Build Along With Me

Practical walkthroughs on Laravel, React, APIs and deployment workflows.

Subscribe on YouTube

How to Create an Event Calendar in Laravel 13

๐Ÿ› ๏ธ Laravel Tutorials5 min read

How to Create an Event Calendar in Laravel 13

Muhammad Yasir Amin

Muhammad Yasir Amin

Senior Full Stack Engineerโ€ขNov 6, 2026
How to Create an Event Calendar in Laravel 13

To build an event calendar in Laravel 13, create an events table and model, add a JSON endpoint that returns events between a start and end date, and load FullCalendar on a Blade page with its events option pointing at that endpoint. FullCalendar sends the visible date range on every navigation, so your server only returns what is needed.

This guide uses Laravel 13 (PHP 8.3 or newer). The same code works on Laravel 12. FullCalendar is a separate JavaScript library, so check its documentation for the current version and installation options.

How does the calendar get its data?

FullCalendar can load events from a URL. When the user changes month or view, it requests that URL with start and end query parameters in ISO 8601 format. Your controller filters events that overlap this range and returns JSON objects with at least title and start.

Step 1: How do I create the model and table?

Code
php artisan make:model Event -m
Shell
Schema::create('events', function (Blueprint $table) {
    $table->id();
    $table->string('title');
    $table->dateTime('starts_at');
    $table->dateTime('ends_at');
    $table->timestamps();

    $table->index(['starts_at', 'ends_at']);
});

The index speeds up the range query as the table grows. Then set fillable fields and casts on the model:

JavaScript
namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Event extends Model
{
    protected $fillable = ['title', 'starts_at', 'ends_at'];

    protected function casts(): array
    {
        return [
            'starts_at' => 'datetime',
            'ends_at' => 'datetime',
        ];
    }
}

Run php artisan migrate to create the table.

Step 2: How do I build the JSON feed?

JavaScript
namespace App\Http\Controllers;

use App\Models\Event;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;

class CalendarFeedController extends Controller
{
    public function __invoke(Request $request): JsonResponse
    {
        $data = $request->validate([
            'start' => ['required', 'date'],
            'end' => ['required', 'date', 'after_or_equal:start'],
        ]);

        $events = Event::query()
            ->where('starts_at', '<', $data['end'])
            ->where('ends_at', '>=', $data['start'])
            ->get(['id', 'title', 'starts_at', 'ends_at'])
            ->map(fn (Event $e) => [
                'id' => $e->id,
                'title' => $e->title,
                'start' => $e->starts_at->toIso8601String(),
                'end' => $e->ends_at->toIso8601String(),
            ]);

        return response()->json($events);
    }
}

The two where clauses return any event that overlaps the range, including events that start before it and end inside it. I ran php -l on this controller. I did not execute it against a database or a browser for this article.

Add the routes:

CSS
use App\Http\Controllers\CalendarFeedController;

Route::view('/calendar', 'calendar')->middleware('auth');
Route::get('/calendar/feed', CalendarFeedController::class)->middleware('auth');

Step 3: How do I show the calendar in Blade?

Create resources/views/calendar.blade.php. Load FullCalendar from a CDN or from npm, following its documentation, then initialise it:

JavaScript
<div id="calendar"></div>

<script>
document.addEventListener('DOMContentLoaded', function () {
    const calendar = new FullCalendar.Calendar(document.getElementById('calendar'), {
        initialView: 'dayGridMonth',
        headerToolbar: {
            left: 'prev,next today',
            center: 'title',
            right: 'dayGridMonth,timeGridWeek,listWeek'
        },
        events: '/calendar/feed'
    });
    calendar.render();
});
</script>

How do I let users add events?

Keep it simple first: a normal form that posts to a store route with validation, then redirects back to the calendar.

JavaScript
public function store(Request $request): RedirectResponse
{
    $data = $request->validate([
        'title' => ['required', 'string', 'max:120'],
        'starts_at' => ['required', 'date'],
        'ends_at' => ['required', 'date', 'after:starts_at'],
    ]);

    Event::create($data);

    return redirect('/calendar');
}

FullCalendar also supports clicking a date and editing events, but those features need extra JavaScript and more routes for update and delete. Add them only when you need them, and protect each route with authorization.

What about time zones?

Store datetimes in UTC and convert for display. Laravel's app.timezone setting controls the default. FullCalendar has its own timeZone option, so make sure the feed and the calendar agree. A mismatch makes events appear hours off.

How do I verify it works?

  1. Insert two events with php artisan tinker: one this month, one next month.
  2. Open /calendar. Only the current month's event should show.
  3. Click next. The next month's event appears, and the network tab shows a new request to /calendar/feed with different start and end values.
  4. Request the feed without parameters. You should get a 422 validation response.

What are the common mistakes?

  • Returning every event. It works at first and slows down as data grows. Filter by the range.
  • Wrong keys in JSON. FullCalendar expects start, not starts_at.
  • Time zone drift. Keep one convention for storage and display.
  • Missing auth on the feed. If events are private, the JSON route must be protected too.
  • Using a reserved class name. Naming a model Event can clash with imports of the Event facade. Use an alias or a more specific name such as CalendarEvent in larger apps.

FAQ

Do I need a package for a calendar in Laravel?

No. A model, a JSON route and a JavaScript calendar library such as FullCalendar are enough for most cases.

Can events repeat weekly?

FullCalendar supports recurring events through its rules, or you can generate occurrences on the server for the requested range. Start with single events and add recurrence later.

Can I use Livewire or Inertia instead?

Yes. The server side stays the same: a validated range query returning event data. Only the front-end wiring changes.

References

Article Index & Topic Tags
LaravelEloquentCalendarFullcalendar

YouTube Channel

Build Along With Me

Practical walkthroughs on Laravel, React, APIs and deployment workflows.

Muhammad Yasir Amin
Available for Contracts
Author & Solutions Architect

Senior Full Stack Engineer

Independent Senior Full Stack Engineer working on Laravel, React and Next.js applications, APIs and delivery workflows.

Laravel & PHP ApplicationsReact & Next.js InterfacesREST APIs & IntegrationsDatabase Queries & DebuggingDocker Development WorkflowsClear Scope & Handover
Discuss Your Next Step

What Does Your Application Need Next?

Share your current system, the problem you want to solve and what a useful result looks like. We can identify the right starting point and agree on a practical scope.

Technical Audit

Find the Next Useful Fix

Application Development

Scoped, Reviewable Milestones

Ongoing Support

Agreed Capacity and Priorities

Share your goals, current stack and requirements before the call.