My app felt slow loading individual idea pages. Not broken — just sluggish. The kind of thing where you notice the delay but wouldn’t know where to start looking.
So I asked one question:
“the app feels a little slow when loading an individual idea, is there anything obvious in the code that could be having a negative impact on performance?”
Claude Code scanned the page’s code — the Livewire component, the Blade template, the models, and their relationships — and came back with 9 issues, prioritised by severity. I didn’t need to know what to look for. I just needed to ask.
If your Laravel app feels slow, try the same prompt on your slowest page. Here’s what it found on mine.
Table of contents
Open Table of contents
- The prompt that finds performance issues
- Critical: hidden component making API calls on every page load
- Critical: model $appends triggering HTTP requests on serialization
- High: expensive query in render() instead of mount()
- High: serializing an entire model unnecessarily
- Medium: missing eager-loading (N+1 queries)
- Medium: comments loading in a hidden modal
- The full list
- Key takeaway
The prompt that finds performance issues
Before getting into the fixes, this is the important part. You don’t need to be a performance expert. You don’t need to know about N+1 queries or Livewire dehydration cycles. You just need to ask:
“This page feels slow — is there anything obvious in the code that could be having a negative impact on performance?”
Paste a URL or point to the component file. The AI will read the code, trace the data flow, and identify bottlenecks you’d never think to look for. The 9 issues below were all found from that single question.
Critical: hidden component making API calls on every page load
The idea edit page had a slide-over panel for AI-powered hypothesis building. The panel was hidden by default — but the Livewire component behind it still mounted on every page load.
// This runs on EVERY page load, even when the panel is hidden
public function mount(): void
{
$conversation = Conversation::query()->create([...]);
$this->js('$nextTick(() => $wire.streamResponse())');
}
Every time someone opened an idea, the app was creating a database record and firing an API call to OpenAI — for a feature the user hadn’t opened. This was the single biggest performance hit.
The fix
Don’t mount the component until the user actually opens the panel. Alpine’s x-if directive only renders the component when the condition is true:
<!-- Before: component mounts immediately, even when hidden -->
<livewire:hypothesis-ai-chat />
<!-- After: component only mounts when panel is opened -->
<template x-if="open">
<livewire:hypothesis-ai-chat />
</template>
The lesson: Livewire components inside hidden modals, slide-overs, and panels still mount and run their logic. If a component makes API calls or database queries on mount, it’s doing that work on every page load whether the user sees it or not.
Critical: model $appends triggering HTTP requests on serialization
The Goal model had appended attributes that fetched external data:
protected $appends = [
'last_month_data', // Makes an HTTP request
'previous_28_days_data', // Makes an HTTP request
'statusColor',
];
Every time a Goal was serialized — toArray(), JSON encoding, or Livewire’s dehydration cycle — these attributes triggered up to 3 external HTTP requests. And Goals were being serialized multiple times per page load across different components.
The lesson: $appends on Eloquent models run every time the model is serialized. If an appended attribute makes an API call or runs an expensive query, that cost multiplies every time the model passes through Livewire’s render cycle.
High: expensive query in render() instead of mount()
The component’s render() method was querying all idea IDs to calculate previous/next navigation:
// This runs on EVERY Livewire re-render, not just the first load
public function render()
{
$allIdeaIds = (clone $baseQuery)->pluck('id')->toArray();
$currentPosition = array_search($this->idea->id, $allIdeaIds);
// ...
}
In Livewire, render() runs on every update — every form field change, every button click, every poll interval. Expensive queries here multiply fast.
The lesson: Put expensive queries in mount() (runs once) rather than render() (runs on every update). If the data doesn’t change between updates, it shouldn’t be recalculated.
High: serializing an entire model unnecessarily
The Like component received a full Idea model and immediately called toArray():
public function mount(Idea $idea)
{
$this->record = $idea->toArray();
}
This serialized the entire Idea — including its Goal relationship, which triggered the $appends HTTP requests described above. The Like component only needed the idea’s ID and whether the current user had liked it.
The lesson: Don’t pass entire models to components that only need a few fields. Pass just the data you need.
Medium: missing eager-loading (N+1 queries)
The template accessed $idea->author without eager-loading the relationship. Each idea loaded its author with a separate query — the classic N+1 problem.
The lesson: If your template accesses a relationship (like $idea->author->name), make sure it’s eager-loaded with ->with('author') in the query.
Medium: comments loading in a hidden modal
The comments component queried all comments on mount, even though comments were inside a modal that the user might never open.
The lesson: Same pattern as the AI chat — hidden modals still mount their Livewire components. Either lazy-load with x-if, use Livewire’s #[Lazy] attribute, or move the query to a method that only runs when the modal opens.
The full list
| # | Issue | Severity | Root cause |
|---|---|---|---|
| 1 | AI chat mounting on every page load | Critical | Hidden component still mounts |
| 2 | Model $appends making HTTP requests | Critical | Serialization triggers API calls |
| 3 | Query in render() instead of mount() | High | Runs on every Livewire update |
| 4 | Full model serialization in Like component | High | toArray() cascades through relationships |
| 5 | Missing author eager-load | Medium | N+1 query |
| 6 | Comments loading in hidden modal | Medium | Hidden component still mounts |
| 7 | All goals loaded as public property | Low | Potential $appends trigger |
| 8 | wire:poll.2s compounding render cost | Low | Polls trigger full re-renders |
| 9 | Team members loaded eagerly | Low | Computed property loads all users |
Key takeaway
You don’t need to be a performance expert to find and fix slow pages. Ask your AI assistant one question — “this page feels slow, what’s obvious?” — and let it trace the code for you. The most common patterns: components that mount when they shouldn’t, models that trigger expensive operations on serialization, and queries that run on every update instead of once on load.