# How to Seed Initial Data into the Database with GORM in golang-clean-architecture

> Learn to seed initial data into your database using GORM in a golang clean architecture project. Create a dedicated seed command to easily populate your database with GORM.

- Repository: [manato/golang-clean-architecture](https://github.com/manakuro/golang-clean-architecture)
- Tags: how-to-guide
- Published: 2026-03-06

---

**Seeding initial data into the database with GORM in a Clean Architecture project involves creating a standalone command in [`cmd/seed/main.go`](https://github.com/manakuro/golang-clean-architecture/blob/main/cmd/seed/main.go) that loads configuration, initializes a GORM database connection via `datastore.NewDB()`, and persists domain entities using `db.Create()`.**

The `manakuro/golang-clean-architecture` repository demonstrates how to implement database seeding while maintaining strict separation of concerns across Clean Architecture layers. This approach keeps your seeding logic isolated from business logic and ensures your database initializes with required reference data every time you spin up a new environment.

## Understanding the Clean Architecture Layers for Database Seeding

The repository organizes code into distinct layers that collaborate to seed initial data into the database with GORM:

- **Configuration (`pkg/config`)**: The `config.ReadConfig()` function parses environment variables into `config.C`, providing database credentials and connection parameters.
- **Domain (`pkg/domain/model`)**: Defines core entities like the `User` struct in [`pkg/domain/model/user.go`](https://github.com/manakuro/golang-clean-architecture/blob/main/pkg/domain/model/user.go), which maps directly to database tables via GORM tags.
- **Infrastructure (`pkg/infrastructure/datastore`)**: Contains `datastore.NewDB()` in [`pkg/infrastructure/datastore/db.go`](https://github.com/manakuro/golang-clean-architecture/blob/main/pkg/infrastructure/datastore/db.go), which constructs the MySQL DSN and returns an initialized `*gorm.DB` instance.
- **Entry Points (`cmd/seed`)**: The standalone [`main.go`](https://github.com/manakuro/golang-clean-architecture/blob/main/main.go) file in `cmd/seed/` orchestrates the seeding process without coupling to the main application server.

## Step-by-Step Guide to Seeding Initial Data with GORM

### Load Application Configuration

Before connecting to the database, invoke `config.ReadConfig()` to populate the global configuration struct. This ensures the seeder uses the same database credentials as your main application.

```go
config.ReadConfig()

```

### Initialize the GORM Database Connection

Call `datastore.NewDB()` to build the connection. This function reads `config.C.Database` parameters (host, port, user, password, database name) and returns a configured `*gorm.DB` pointer.

```go
db := datastore.NewDB()
defer db.Close()

```

Enable SQL logging during development by calling `db.LogMode(true)` immediately after initialization.

### Define Domain Entities

Instantiate structs from the domain layer. For example, create a `User` value defined in [`pkg/domain/model/user.go`](https://github.com/manakuro/golang-clean-architecture/blob/main/pkg/domain/model/user.go):

```go
user := &model.User{
    ID:   1,
    Name: "Tom",
    Age:  "20",
}

```

GORM automatically manages `created_at` and `updated_at` timestamps when these fields exist on the struct.

### Persist Data Using GORM

Insert the record using `db.Create()`. This method generates and executes the appropriate SQL INSERT statement.

```go
if err := db.Create(user).Error; err != nil {
    log.Fatalf("failed to seed user data: %v", err)
}

```

For bulk operations, pass a slice of structs to `Create()`:

```go
users := []model.User{
    {ID: 1, Name: "Tom",  Age: "20"},
    {ID: 2, Name: "Anna", Age: "25"},
    {ID: 3, Name: "Mike", Age: "30"},
}
if err := db.Create(&users).Error; err != nil {
    log.Fatalf("bulk seed failed: %v", err)
}

```

## Complete Seeding Implementation Example

The following implementation from [`cmd/seed/main.go`](https://github.com/manakuro/golang-clean-architecture/blob/main/cmd/seed/main.go) demonstrates the complete workflow for seeding initial data into the database with GORM:

```go
package main

import (
	"log"

	"golang-clean-architecture/pkg/config"
	"golang-clean-architecture/pkg/domain/model"
	"golang-clean-architecture/pkg/infrastructure/datastore"
)

func main() {
	// 1️⃣ Load configuration
	config.ReadConfig()

	// 2️⃣ Initialise GORM DB (MySQL)
	db := datastore.NewDB()
	db.LogMode(true) // optional: enable SQL logging
	defer db.Close()

	// 3️⃣ Define a user to seed
	user := &model.User{
		ID:   1,
		Name: "Tom",
		Age:  "20",
		// timestamps are left nil – GORM will fill them automatically
	}

	// 4️⃣ Persist the user
	if err := db.Create(user).Error; err != nil {
		log.Fatalf("failed to seed user data: %v", err)
	}
}

```

Run this seeder independently without starting the main application server:

```bash
go run ./cmd/seed

```

## Key Files and Their Roles in the Seeding Process

| Layer | File | Role |
|-------|------|------|
| **Entry point** | [`cmd/seed/main.go`](https://github.com/manakuro/golang-clean-architecture/blob/main/cmd/seed/main.go) | Orchestrates config loading, DB creation, and data insertion. |
| **Infrastructure** | [`pkg/infrastructure/datastore/db.go`](https://github.com/manakuro/golang-clean-architecture/blob/main/pkg/infrastructure/datastore/db.go) | Builds the GORM DB connection from config values via `NewDB()`. |
| **Domain model** | [`pkg/domain/model/user.go`](https://github.com/manakuro/golang-clean-architecture/blob/main/pkg/domain/model/user.go) | Defines the `User` entity mapped to the `users` table. |
| **Configuration** | [`pkg/config/config.go`](https://github.com/manakuro/golang-clean-architecture/blob/main/pkg/config/config.go) | Holds DB credentials and other settings used by `NewDB()`. |

## Summary

- **Seeding initial data into the database with GORM** requires a standalone entry point in [`cmd/seed/main.go`](https://github.com/manakuro/golang-clean-architecture/blob/main/cmd/seed/main.go) that operates independently from your main application.
- The `datastore.NewDB()` function in [`pkg/infrastructure/datastore/db.go`](https://github.com/manakuro/golang-clean-architecture/blob/main/pkg/infrastructure/datastore/db.go) centralizes database connection logic, ensuring seeders and the main app use identical connection parameters.
- Use `db.Create()` to insert single records or bulk slices; GORM automatically handles timestamp fields when defined in your domain models.
- Keeping seeding logic in a separate `main` package under `cmd/seed` maintains Clean Architecture principles by isolating infrastructure concerns from domain logic.

## Frequently Asked Questions

### How do I run the database seeder independently from the main application?

Execute `go run ./cmd/seed` from the project root. This compiles and runs only the seeding logic in [`cmd/seed/main.go`](https://github.com/manakuro/golang-clean-architecture/blob/main/cmd/seed/main.go) without starting the main HTTP server or other application services, making it ideal for CI/CD pipelines or local development setup.

### What is the role of the `datastore.NewDB()` function in the seeding process?

`datastore.NewDB()` acts as a factory that constructs a `*gorm.DB` instance using credentials from `config.C.Database`. Located in [`pkg/infrastructure/datastore/db.go`](https://github.com/manakuro/golang-clean-architecture/blob/main/pkg/infrastructure/datastore/db.go), this function ensures the seeder connects to MySQL with the same DSN format and connection pooling settings used by the production application.

### Can I seed multiple tables or bulk data using this approach?

Yes. Pass a slice of structs to `db.Create(&slice)` instead of a single pointer. For example, define `users := []model.User{{...}, {...}}` and call `db.Create(&users)` to insert all records in a single transaction. You can extend [`cmd/seed/main.go`](https://github.com/manakuro/golang-clean-architecture/blob/main/cmd/seed/main.go) to seed multiple tables by repeating the create logic for each domain model.

### How does Clean Architecture benefit database seeding compared to traditional approaches?

Clean Architecture isolates seeding logic in [`cmd/seed/main.go`](https://github.com/manakuro/golang-clean-architecture/blob/main/cmd/seed/main.go), keeping it separate from business logic in `pkg/domain` and infrastructure details in `pkg/infrastructure`. This separation means you can modify seed data without touching core application code, swap database drivers by changing only `datastore.NewDB()`, and test seeding logic independently using mock configurations.