DEV Community

ludovic dillieux
ludovic dillieux

Posted on

5 Laravel Migration Mistakes That Cost Me 3 Days (And How You Can Avoid Them)

Learning Laravel while building a real beekeeping app taught me these lessons the hard way.


Last week, I spent 3 frustrating days debugging migration issues while building BeeNote, my beekeeping management app. What should have been a simple database setup turned into a PostgreSQL nightmare.

Here are the 5 mistakes that cost me the most time – and the solutions that finally worked.

1. The Duplicate Index Trap 🪤

The Mistake:

Schema::create('photos', function (Blueprint $table) {
    $table->morphs('photoable'); 
    $table->index(['photoable_type', 'photoable_id']); // DUPLICATE!
});
Enter fullscreen mode Exit fullscreen mode

The Error:

SQLSTATE[42P07]: Duplicate table: relation "photos_photoable_type_photoable_id_index" already exists
Enter fullscreen mode Exit fullscreen mode

The Fix:
Laravel’s morphs() method automatically creates the index. Don’t add it manually.

Schema::create('photos', function (Blueprint $table) {
    $table->morphs('photoable'); // Index created automatically
    $table->index('ordre'); // Only additional indexes
});
Enter fullscreen mode Exit fullscreen mode

Time saved: 4 hours of PostgreSQL debugging.

2. Wrong Data Types for GPS Coordinates 🗺️

The Mistake:

$table->float('latitude');  // Precision loss!
$table->float('longitude'); // Your beehives will "move" 10 meters
Enter fullscreen mode Exit fullscreen mode

The Fix:

$table->decimal('latitude', 10, 8);  // 47.12345678 - exact precision
$table->decimal('longitude', 11, 8); // -1.23456789 - no drift
Enter fullscreen mode Exit fullscreen mode

When you’re tracking beehive locations, 10-meter precision errors aren’t acceptable.

3. Forgetting Business Logic in ENUMs 📝

The Mistake:

$table->string('queen_color'); // Free text = chaos
// Users input: "blue", "Blue", "BLUE", "bleu", "azul"...
Enter fullscreen mode Exit fullscreen mode

The Fix:

$table->enum('couleur_marquage_reine', [
    'blanc', 'jaune', 'rouge', 'vert', 'bleu'
])->nullable(); // International beekeeping color code
Enter fullscreen mode Exit fullscreen mode

Real beekeeping uses standardized queen marking colors. Research your domain!

4. Performance Killer: Missing Composite Indexes 🐌

The Problem:
50ms query time on 10k+ records because I didn’t think about real-world usage patterns.

The Solution:

// Users frequently filter by: their tasks + status
$table->index(['user_id', 'statut']); // Composite index

// Query time: 50ms → 2ms
Enter fullscreen mode Exit fullscreen mode

Think about your WHERE clauses before you have performance problems.

5. Wrong Cascade Strategy = Data Loss 💥

The Mistake:

$table->foreignId('visite_id')
      ->constrained()
      ->onDelete('cascade'); // DESTROYS history!
Enter fullscreen mode Exit fullscreen mode

The Fix:

$table->foreignId('visite_id')
      ->constrained()
      ->onDelete('set null'); // Keeps history, breaks link
Enter fullscreen mode Exit fullscreen mode

When a visit gets deleted, I want to keep the task history – just remove the connection.


The Real Learning: Domain Knowledge Matters

Building BeeNote taught me that migrations aren’t just technical – they tell the story of your business logic.

My visits table has 47 columns because beekeeping is complex:

  • Weather conditions affect bee behavior
  • Queen marking follows international standards
  • Varroa mite counts determine treatment timing
  • etc.

The technical complexity reflects the real-world complexity.


What’s Next?

These 5 mistakes were just the beginning. I documented the complete migration journey – including the full PostgreSQL schema, performance optimizations, and why I chose VILT stack over TALL stack for this project.

Read the full technical deep-dive here (warning: it’s detailed, includes all the code, and explains the beekeeping business logic behind each decision)

Currently building this in public as I transition from employee to freelance Laravel developer. Following my progress? Find me on X/Twitter @Llieudi.


What migration mistakes have cost you the most time? Drop them in the comments – let’s learn from each other’s pain! 😅

Top comments (0)