Overview
This guide shows you how to use Qovery Lifecycle Jobs to seed your PostgreSQL database with SQL scripts. This approach is ideal for initializing databases with sample data, setting up database schemas, or restoring database backups during deployment.Prerequisites
- A Qovery account with an environment set up
- A PostgreSQL database deployed in your Qovery environment
- A SQL script file for seeding your database
- Basic knowledge of Docker and shell scripting
Goal
Set up an automated database seeding process that runs when your environment starts, using a secure approach that downloads SQL scripts from external storage (like S3) and executes them against your PostgreSQL database.Architecture Overview
The solution consists of three main components:- Dockerfile: Builds a container with PostgreSQL client and curl
- Seed Script: Shell script that downloads and executes SQL files
- Lifecycle Job: Qovery job configured to run at environment start
Step 1: Prepare Your SQL Script
First, prepare your SQL script and store it in a secure location.Create Your SQL Script
Upload to Secure Storage
Step 2: Create the Seeding Script
Create a shell script that will download and execute your SQL file.Create seed.sh
seed.sh with the following content:- psql: Used for plain SQL files (.sql)
- pg_restore: Used for custom PostgreSQL dump formats (.dump, .backup)
Make Script Executable
Step 3: Create the Dockerfile
Create a Dockerfile that packages the seeding script with required dependencies.Create Dockerfile
Dockerfile:Create Repository Structure
Push to Git Repository
Step 4: Create Lifecycle Job in Qovery
Now create the Lifecycle Job in the Qovery Console.Open Qovery Console
Create New Lifecycle Job

Configure Repository
- Name:
database-seed - Source: Select your Git provider and repository
- Branch:
main(or your default branch) - Root application path: Leave empty if Dockerfile is at root, or specify path if in subdirectory
Configure Build Settings
- Build mode: Docker
- Dockerfile path:
Dockerfile
Select Lifecycle Event
- Event: Select START
- START: Run when environment starts
- STOP: Run when environment stops
- DELETE: Run when environment is deleted
Configure Job Settings
- Number of restarts: 0 (job should run once and complete)
- Max duration: 300 seconds (adjust based on your database size)
- Port: Leave empty (not needed for this job)
- CMD Arguments:
["seed.sh"]
Configure Resources
- CPU: 0.5 vCPU (adjust based on database size)
- Memory: 512 MB (adjust based on SQL file size)

Create Without Deploying
Step 5: Configure Environment Variables
Configure the environment variables required by your seeding script.Open Variables Section

Add DATABASE_URL
- Variable:
DATABASE_URL - Value: Use the built-in alias from your PostgreSQL service
- Type: Alias
$QOVERY_DATABASE_YOUR_DB_NAME_CONNECTION_URI. This automatically provides the connection string.Add SEED_URL
- Variable:
SEED_URL - Value: The URL to your SQL script (e.g., S3 presigned URL)
- Type: Secret (if URL contains sensitive information)
Add RESTORE_METHOD
- Variable:
RESTORE_METHOD - Value:
psql(for plain SQL files) orpg_restore(for PostgreSQL dumps) - Type: Value
- Use
psqlfor.sqlfiles created withpg_dump --format=plain - Use
pg_restorefor.dumpor.backupfiles created withpg_dump --format=custom
Step 6: Deploy and Test
Deploy your Lifecycle Job and verify it works correctly.Deploy the Lifecycle Job
Monitor Deployment
Trigger the Job
- You deploy or redeploy your environment
- You start a stopped environment
- The START event is triggered
Check Job Logs

Verify Database Contents
Advanced Scenarios
Idempotent Seeding
To make your seeding script safe to run multiple times, use idempotent SQL commands:Using Multiple SQL Files
Modify your seed script to handle multiple SQL files:Conditional Seeding
Only seed if database is empty:Environment-Specific Seeds
Use different seed files for different environments:Troubleshooting
Job Fails with “psql: command not found”
Issue: PostgreSQL client not installed in container Solution: Verify your Dockerfile installspostgresql-client:
Connection Timeout to Database
Issue: Cannot connect to database from Lifecycle Job Checklist:- ✅ Database is deployed and running
- ✅
DATABASE_URLenvironment variable is correctly set - ✅ Database and Lifecycle Job are in the same environment
- ✅ Network connectivity between services is enabled
SQL File Download Fails
Issue: Cannot download SQL file from storage Solution:- Verify the
SEED_URLis correct and accessible - Check if presigned URLs have expired (regenerate if needed)
- Ensure the container has network access to external URLs
- Test the URL manually with curl
Duplicate Key Errors
Issue: Seeding fails with duplicate key violations Solution: Use idempotent SQL commands:Job Runs Too Long and Times Out
Issue: Seeding job exceeds max duration Solution:- Increase the Max duration in job settings
- Optimize your SQL script (use COPY instead of INSERT for large datasets)
- Split large seeds into multiple smaller files
- Consider using
pg_restorewith parallel jobs flag for large dumps
Best Practices
Store Secrets Securely
Store Secrets Securely
- Use presigned URLs with expiration for S3
- Store SQL files in private buckets with IAM authentication
- Use Qovery Secrets for sensitive environment variables
- Rotate presigned URLs regularly
Make Seeds Idempotent
Make Seeds Idempotent
- Use
CREATE TABLE IF NOT EXISTS - Use
INSERT ... ON CONFLICT DO NOTHING - Check for existing data before inserting
- Use transactions to ensure all-or-nothing execution
Environment-Specific Data
Environment-Specific Data
- Minimal data for development
- Realistic test data for staging
- Migration scripts only for production
- Use environment variables to select appropriate seeds
Monitor Job Execution
Monitor Job Execution
- Verify successful completion in Qovery logs
- Check database contents after seeding
- Set up alerts for job failures
- Review execution time to optimize performance
Version Control Your Seeds
Version Control Your Seeds
- Keep seed SQL files in version control
- Use semantic versioning for seed files
- Document changes in commit messages
- Tag releases that include seed changes
Test Before Production
Test Before Production
- Test with preview environments
- Verify on staging before production
- Test rollback procedures
- Document the seeding process
Alternative Approaches
Using Database Migrations
For schema changes and ongoing database updates, consider using migration tools instead:- Flyway: Version-controlled database migrations
- Liquibase: Database-independent migration management
- Alembic: Python-based migration tool for SQLAlchemy
- TypeORM/Sequelize: Built-in migration support for Node.js
Using Qovery Clone Environment
For duplicating existing data:- Create a database backup in your source environment
- Use Qovery’s Clone Environment feature
- The cloned environment includes database snapshots
Using Init Containers (Helm)
If deploying with Helm charts, use init containers:Additional Resources
Lifecycle Jobs Documentation
Environment Variables
PostgreSQL Database
Example Repository
Next Steps
Now that you’ve set up database seeding, you can:- Create environment-specific seed files for development, staging, and production
- Implement database migrations for schema changes
- Set up automated testing with seeded test data
- Use Preview Environments with fresh seed data for each PR
- Explore other Lifecycle Job use cases (backups, cleanup, monitoring)