Laravel & PHP ← Back to blog

Seeding Demo vs Generated Content in a Laravel Docker Container

03 May 2026 · Matt

How the DatabaseSeeder switches between demo posts and AI-generated content based on a base64 environment variable.

Two Seeding Paths

The CMS needs to work in two modes: a static demo (for the IONOS VPS and local dev) and an AI-generated deployment (for AWS). The seeder checks for a GENERATED_CONTENT_B64 environment variable to decide which path to take.

public function run(): void
{
    $b64 = env('GENERATED_CONTENT_B64');
    if ($b64) {
        $this->seedGeneratedPosts($b64);
        return;
    }
    $this->seedBlogTypes();
    $this->seedPages();
    $this->seedDemoPosts();
}

Passing JSON via Base64

The content generator in the Django CMS manager produces a JSON blob. Before deploying, it's base64-encoded and passed as an environment variable — Docker Compose and ECS task definitions both support this pattern cleanly.

# In the Django CMS manager (Python):
import base64, json

content = generate_with_images(site)
b64 = base64.b64encode(json.dumps(content).encode()).decode()
# b64 is then set as GENERATED_CONTENT_B64 in the ECS task definition

firstOrCreate vs updateOrCreate

Demo posts use firstOrCreate so re-seeding doesn't overwrite manual edits. Generated posts use updateOrCreate because the content comes from the AI pipeline and should always reflect the latest generation.

// Demo — preserve manual edits
Post::firstOrCreate(['slug' => $p['slug']], $p);

// Generated — always apply latest AI output
Post::updateOrCreate(['slug' => $postData['slug']], [...]);

The Entrypoint

The Docker entrypoint runs migrations and seeds on every container start. This means a fresh ECS task always has up-to-date content without needing a separate migration step.

#!/bin/bash
php artisan storage:link --force
php artisan migrate --force
php artisan db:seed --force
php-fpm
Tip: php artisan storage:link --force creates the public/storage symlink needed to serve locally-uploaded files. Add --force so it doesn't fail if the symlink already exists from a previous container run.