If you write code for a living, you don’t need fluffy “prompt lists.” You need repeatable patterns that turn vague tickets into shippable Laravel code—migrations, tests, controllers, jobs, Eloquent queries, the works. This guide is written from a developer’s point of view and uses Laravel in every example.
A tiny framework that makes prompts work
When you ask for code, include these six pieces (I remember them as TARGET):
- Task — what you want, one sentence.
- Audience/Role — who the model should be (“Laravel staff engineer,” “SRE,” etc.).
- Runtime — Laravel/PHP versions, packages, DB.
- Guardrails — limits (no facades, prefer contracts, PSR-12, no macros, etc.).
- Examples — a small “before → after” if style matters.
- Tests — ask for tests up front and the format (Pest or PHPUnit).
Also say how you want the output (single file, unified diff, JSON, etc.). That’s the “cheatcode” most lists miss.
1) Scaffold: from ticket to running code
Prompt
Role: Laravel staff engineer.
Task: CRUD forProjectwith soft deletes and policy-based auth.
Runtime: Laravel 11, PHP 8.3, MySQL. Use Pest, Form Requests, API Resources.
Guardrails: no mass-assignable*; validate at boundaries; return 422 on validation errors.
Output: migration, model, controller, form requests, resource, routes, Pest tests (API). Single code blocks per file.
Typical output (edited for brevity)
// database/migrations/2025_01_01_000000_create_projects_table.php
return new class extends Migration {
public function up(): void {
Schema::create('projects', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->text('description')->nullable();
$table->foreignId('owner_id')->constrained('users');
$table->timestamps();
$table->softDeletes();
});
}
};
// app/Models/Project.php
class Project extends Model
{
use HasFactory, SoftDeletes;
protected $fillable = ['name','description','owner_id'];
public function owner(): BelongsTo { return $this->belongsTo(User::class,'owner_id'); }
}
// app/Http/Requests/StoreProjectRequest.php
class StoreProjectRequest extends FormRequest {
public function authorize(): bool { return $this->user()->can('create', Project::class); }
public function rules(): array {
return ['name'=>'required|string|max:120', 'description'=>'nullable|string', 'owner_id'=>'required|exists:users,id'];
}
}
// app/Http/Resources/ProjectResource.php
class ProjectResource extends JsonResource {
public function toArray($request): array {
return [
'id'=>$this->id, 'name'=>$this->name, 'description'=>$this->description,
'owner'=>['id'=>$this->owner_id, 'name'=>$this->owner->name],
'created_at'=>$this->created_at->toAtomString(),
];
}
}
// app/Http/Controllers/ProjectController.php
class ProjectController extends Controller
{
public function index(): AnonymousResourceCollection {
$projects = Project::query()->with('owner')->latest()->paginate(15);
return ProjectResource::collection($projects);
}
public function store(StoreProjectRequest $request): ProjectResource {
$project = Project::create($request->validated());
$this->authorize('view', $project);
return new ProjectResource($project->load('owner'));
}
public function show(Project $project): ProjectResource {
$this->authorize('view', $project);
return new ProjectResource($project->load('owner'));
}
public function update(UpdateProjectRequest $request, Project $project): ProjectResource {
$this->authorize('update', $project);
$project->update($request->validated());
return new ProjectResource($project->load('owner'));
}
public function destroy(Project $project): JsonResponse {
$this->authorize('delete', $project);
$project->delete();
return response()->json(status: 204);
}
}
// routes/api.php
Route::apiResource('projects', ProjectController::class)->middleware('auth:sanctum');
// tests/Feature/ProjectApiTest.php (Pest)
it('creates a project', function () {
$user = User::factory()->create();
actingAs($user);
$payload = ['name'=>'Roadmap','owner_id'=>$user->id];
$res = postJson('/api/projects', $payload)->assertCreated();
$res->assertJsonPath('data.name', 'Roadmap');
});
Why this works: you constrained the output (files and test style) and asked for auth, validation, and resources—so the result is much closer to “drop in and run.”
2) Debugging: from stack trace to minimal fix
Prompt
Role: Laravel debugger.
Task: Identify the root cause of the N+1 warning onGET /api/projects.
Context: Controller + Resource pasted below.
Output: (1) ranked hypotheses, (2) minimal repro in one file (sqlite memory), (3) unified diff for the fix, (4) Pest test failing → passing.
Likely patch
- $projects = Project::query()->latest()->paginate(15);
+ $projects = Project::query()->with('owner')->latest()->paginate(15);
Bonus: Ask ChatGPT to produce a tiny sqlite-based repro script using Laravel’s RefreshDatabase trait so you can reproduce in seconds.
3) Refactors you can trust
Prompt
Role: Staff engineer for maintainability.
Task: Refactor this 70-line controller method into smaller pure functions and a service.
Guardrails: return a unified diff only, no behavior change, PSR-12, prefer early returns, extract validation into Form Request.
Output: (a) diff, (b) 3 bullets explaining design trade-offs.
You’ll get a tight patch instead of a wall of new code.
4) Safer Eloquent & query optimization
Prompt
Role: Database specialist.
Task: Optimize queries for theProjectindex with filters: owner, search “name like %q%”, andwithCount('tasks')sorted bytasks_count desc.
Output: Eloquent example + raw SQL, indexes to add, and anEXPLAINinterpretation.
Possible implementation
$projects = Project::query()
->when($ownerId, fn($q) => $q->where('owner_id', $ownerId))
->when($q, fn($q) => $q->where('name', 'like', "%{$q}%"))
->withCount('tasks')
->orderByDesc('tasks_count')
->with('owner')
->paginate(20);
Indexes to ask for
// 2025_01_01_000001_add_indexes_to_projects.php
Schema::table('projects', function (Blueprint $table) {
$table->index(['owner_id', 'name']); // composite for common filter + search prefix
});
Ask the model to explain why a composite beats two separate single-column indexes for this access pattern.
5) API design with real contracts
Prompt
Role: API designer.
Task: Design REST endpoints for Projects and Project Tasks. Include error codes, validation, pagination, rate-limit notes.
Output: OpenAPI 3.1 YAML + examplecurland a Pest contract test usingIlluminate\Testing\Fluent\AssertableJson.
Contract test sketch
it('lists projects with shape', function () {
actingAs(User::factory()->create());
getJson('/api/projects')
->assertOk()
->assertJson(fn(AssertableJson $json) =>
$json->has('data.0', fn($p) =>
$p->whereAllType([
'id' => 'integer',
'name' => 'string',
'owner.id' => 'integer',
])
)
);
});
6) Jobs, queues, and retries
Prompt
Role: DevOps-minded Laravel engineer.
Task: Create a queued jobSyncProjectToSearchthat syncs a project to Meilisearch.
Guardrails: make it idempotent, exponential backoff, report tofailed_jobs, and expose a command to requeue dead-lettered jobs.
Sketch
// app/Jobs/SyncProjectToSearch.php
class SyncProjectToSearch implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public function __construct(public int $projectId) {}
public function middleware(): array { return [new WithoutOverlapping("sync:project:{$this->projectId}")]; }
public function backoff(): array { return [10, 60, 300]; }
public function handle(MeilisearchClient $client): void {
$project = Project::findOrFail($this->projectId);
$client->index('projects')->updateDocuments([[
'id'=>$project->id, 'name'=>$project->name, 'owner_id'=>$project->owner_id
]]);
}
}
// app/Console/Commands/ReplayFailedJobs.php
class ReplayFailedJobs extends Command
{
protected $signature = 'queue:replay-failed {--limit=50}';
protected $description = 'Replay failed jobs back to the default queue';
public function handle(): int {
FailedJob::query()->limit($this->option('limit'))->each(function ($job) {
dispatch(unserialize($job->payload)); // in practice, deserialize safely
$job->delete();
});
$this->info('Replayed.');
return self::SUCCESS;
}
}
(For production, store a safe, structured payload instead of unserializing blindly.)
7) Validation at the edges
Prompt
Role: API guardian.
Task: Create Form Requests for storing and updating Projects with conditional rules:namerequired on create, optional on update;descriptionmax 10k;owner_idmust be the authenticated user unless role=admin.
Output: two classes + tests.
Tip: Ask ChatGPT to only output the two PHP files and a single Pest file. The constraint keeps things tidy.
8) Security review that’s actually useful
Prompt
Role: AppSec engineer (OWASP/CWE aware).
Task: ReviewProjectControllerandProjectResourcefor common Laravel risks.
Output JSON array of findings with:id,cwe,location,risk,exploit,fix,references.
What to expect: checks for mass assignment, authorization gaps (authorize after create), missing rate limits, unvalidated file uploads, unsafe query building, hidden data leakage in resources, etc. Use the JSON to open tickets automatically.
9) Performance quick wins
- Ask for alternatives to
->count()in loops (prefer eagerwithCount()). - Replace broad
->load('*')with selective relations. - Use
lazyById()for large exports. - Cache per-user lists with tagged caches and
rememberTTLs; request invalidation strategies in the answer. - Ask for benchmarks using
artisan tinkerand microtime blocks—make the model generate the measurement script.
10) Docs devs actually read
Prompt
Role: Tech writer for engineers.
Task: Produce a README withQuickstart,Config,Make targets,Testing,FAQ, andTroubleshootingfor this Laravel app.
Input:composer.json,.env.example, andphp artisanoutput pasted below.
Output: Markdown only.
You’ll get commands that match your scripts instead of generic “php artisan serve.”
One-liners you’ll reuse
- “Explain this stack trace like I’m the on-call, then propose a minimal fix as a diff.”
- “Turn this controller method into a service + form request; return only the diff.”
- “Generate a migration + seeder for 1k realistic Projects using Faker providers.”
- “Property-based tests (Pest +
archtechx/enums) for these invariants: …” - “Write a GitHub Action: run Pest, build Docker, upload coverage artifact, comment status on PR.”
How to avoid hallucinated code
- Pin versions (“Laravel 11, PHP 8.3, Pest 2.x”).
- Constrain output (“return only a unified diff” / “single PHP file”).
- Provide context (config snippets, env, composer packages).
- Ask for tests first—then minimal implementation that makes them pass.
- Request self-review—“run a mental static analysis; list risky lines.”
A final ready-to-paste meta-prompt (Laravel)
Act as a Laravel staff engineer.
Goal: {describe the user story}.
Runtime: Laravel 11, PHP 8.3, MySQL 8, Pest tests.
Guardrails: PSR-12, Form Requests for validation, Policies for auth, API Resources for output,
no broad wildcard mass assignment, eager-load to avoid N+1.
Deliverables (exactly):
1) migration, 2) model, 3) controller, 4) form request(s), 5) resource, 6) routes, 7) Pest tests.
Output: each file in its own code block with the correct path comment at the top.
Finally: a unified diff (if applicable) and a short checklist to verify in local.
Final Conclusion — ChatGPT Cheatcode for Developers
The ChatGPT Cheatcode for Developers isn’t just a collection of prompts — it’s a workflow mindset. For Laravel developers (and really, any coder), ChatGPT becomes a pair-programmer, debugger, reviewer, and teacher rolled into one. When you structure your prompts using frameworks like TARGET, give context (version, stack, guardrails), and demand precise outputs (diffs, tests, or JSON), you transform ChatGPT from a guessing machine into a reliable engineering assistant.
Used wisely, ChatGPT reduces boilerplate, accelerates testing, documents your APIs, and helps you spot edge-cases you might overlook during crunch time. The more specific your instructions, the better it gets at generating production-grade Laravel code — migrations, controllers, or even CI pipelines that just work.
In short: treat ChatGPT like your smartest teammate who works 24/7 and never complains about PSR-12. Master these cheatcodes, and you’ll code faster, debug deeper, and ship cleaner.

Comments