Running Seeders
Learn how to register and run seeders using runner.RunAll() and runner.Run() methods.
Running Seeders
Once you've defined your seeders, use the seeder runner to register and execute them.
Auto-Registration with init()
Similar to migrations, seeders can be auto-registered from init() functions using seeder.AutoRegister(). This is the recommended approach when using migrator.Run().
package seeders
import (
"database/sql"
"github.com/gopackx/go-migration/pkg/seeder"
)
func init() {
seeder.AutoRegister("UserSeeder", &UserSeeder{})
}
type UserSeeder struct{}
func (s *UserSeeder) Run(db *sql.DB) error {
_, err := db.Exec(
"INSERT INTO users (name, email) VALUES ($1, $2)",
"Alice", "alice@example.com",
)
return err
}When using migrator.Run(), auto-registered seeders are discovered automatically — no manual registration needed. Just blank-import the seeders package in your main.go:
package main
import (
"github.com/gopackx/go-migration/pkg/migrator"
_ "your-project/migrations"
_ "your-project/seeders" // triggers init() auto-registration
)
func main() {
migrator.Run()
}seeder.AutoRegister() panics on duplicate names and on empty/whitespace-only names, just like migrator.AutoRegister(). This ensures configuration mistakes are caught at startup.
Manual Registration
For more control, build a Registry, register your seeders on it, then hand it to a Runner:
package main
import (
"database/sql"
"log"
_ "github.com/lib/pq"
"github.com/gopackx/go-migration/pkg/seeder"
"your-project/seeders"
)
func main() {
db, err := sql.Open("postgres", "postgres://user:password@localhost:5432/mydb?sslmode=disable")
if err != nil {
log.Fatal(err)
}
defer db.Close()
reg := seeder.NewRegistry()
if err := reg.Register("UserSeeder", &seeders.UserSeeder{}); err != nil {
log.Fatal(err)
}
if err := reg.Register("PostSeeder", &seeders.PostSeeder{}); err != nil {
log.Fatal(err)
}
if err := reg.Register("RoleSeeder", &seeders.RoleSeeder{}); err != nil {
log.Fatal(err)
}
// The logger may be nil to skip logging.
runner := seeder.NewRunner(reg, db, nil)
// Run all seeders
if err := runner.RunAll(); err != nil {
log.Fatal(err)
}
log.Println("All seeders completed successfully!")
}Registry.Register() returns an error — it wraps seeder.ErrInvalidSeederName for empty names and seeder.ErrDuplicateSeeder for duplicates. Unlike AutoRegister(), it does not panic.
Running All Seeders
runner.RunAll() executes every registered seeder:
if err := runner.RunAll(); err != nil {
log.Fatal(err)
}Execution Order
Without dependencies, seeders run in a deterministic order (sorted by name). Dependencies override this so that a seeder always runs after the seeders it depends on.
Sequential Execution
Each seeder's Run method is called one at a time. If a seeder returns an error, execution stops immediately.
Error Handling
RunAll() returns the first error encountered. Seeders that completed before the failure remain applied.
Running a Specific Seeder
Use runner.Run("SeederName") to execute a single seeder by its registered name:
// Run only the UserSeeder
if err := runner.Run("UserSeeder"); err != nil {
log.Fatal(err)
}This is useful when you need to re-seed a specific table without running all seeders again.
Complete Example
package main
import (
"database/sql"
"log"
"os"
_ "github.com/lib/pq"
"github.com/gopackx/go-migration/pkg/seeder"
"your-project/seeders"
)
func main() {
db, err := sql.Open("postgres", "postgres://user:password@localhost:5432/mydb?sslmode=disable")
if err != nil {
log.Fatal(err)
}
defer db.Close()
reg := seeder.NewRegistry()
for name, s := range map[string]seeder.Seeder{
"UserSeeder": &seeders.UserSeeder{},
"RoleSeeder": &seeders.RoleSeeder{},
"PostSeeder": &seeders.PostSeeder{},
} {
if err := reg.Register(name, s); err != nil {
log.Fatal(err)
}
}
runner := seeder.NewRunner(reg, db, nil)
// Check if a specific seeder was requested
if len(os.Args) > 1 {
name := os.Args[1]
log.Printf("Running seeder: %s", name)
if err := runner.Run(name); err != nil {
log.Fatal(err)
}
} else {
log.Println("Running all seeders...")
if err := runner.RunAll(); err != nil {
log.Fatal(err)
}
}
log.Println("Seeding complete!")
}The name passed to runner.Run() must match the name used in reg.Register() exactly. If the name doesn't match any registered seeder, seeder.ErrSeederNotFound is returned.
What's Next?
- Dependencies — control the execution order of seeders with dependency declarations