DEV Community

Kengo Wada
Kengo Wada

Posted on

3 1

GORM and Goose Migrations

Let's get started with handling migrations in Go with GORM and Goose.

Prerequisites

  • Go installed
  • GORM Supported SQL Database(I'll be using Postgresql)

Note:
You may refer to this repo for the file structure.

Install Goose Locally

Follow the steps here to install Goose for your operating system.

I tried using the installation script with Ubuntu 20.04 but I run into errors and found a solution here

wget http://github.com/golang-migrate/migrate/releases/latest/download/migrate.linux-amd64.deb
sudo dpkg -i migrate.linux-amd64.deb

goose --help // To test if install went well.
Enter fullscreen mode Exit fullscreen mode

Start Dummy Project

  • Create a directory
mkdir app
cd app
Enter fullscreen mode Exit fullscreen mode
  • Initialize it as a Go project
go mod init app
Enter fullscreen mode Exit fullscreen mode
  • Create main.go in the root of your project
package main

func main() {

}
Enter fullscreen mode Exit fullscreen mode

Getting Started With GORM

  • Create database directory
mkdir database
cd database
touch postgres.go
Enter fullscreen mode Exit fullscreen mode
  • Add the following to database/postgres.go
package database

import (
    "database/sql"
    "os"

    "gorm.io/driver/postgres"
    "gorm.io/gorm"
)

var dbURL := os.Getenv("GOOSE_DBSTRING")

var GORM_DB *gorm.DB
var SQL_DB *sql.DB
var DB_MIGRATOR gorm.Migrator

func ConnectToDatabase() (error) {
    db, err := gorm.Open(postgres.Open(dbURL), &gorm.Config{})
    if err == nil {
        GORM_DB = db
        SQL_DB, _ = db.DB()
        DB_MIGRATOR = db.Migrator()
    }
    return err
}
Enter fullscreen mode Exit fullscreen mode
  • At this point you'll have failed import errors, so let's fix that
go mod tidy
Enter fullscreen mode Exit fullscreen mode
  • Now create env in your projects root directory
mkdir env
touch env/goose.env
Enter fullscreen mode Exit fullscreen mode
  • Add the following to env/goose.env
export GOOSE_DRIVER='postgres'
export GOOSE_DBSTRING='postgres://user:password@localhost:5432/db_name?sslmode=disable'
export GOOSE_MIGRATION_DIR='./migrations'
Enter fullscreen mode Exit fullscreen mode
  • Now source the environment variables
source env/goose.env
Enter fullscreen mode Exit fullscreen mode

Creating Models and Migrations

  • Create a models directory in your projects root directory
mkdir models
touch models/user.go
Enter fullscreen mode Exit fullscreen mode
  • Add the following to models/user.go
package models

import (
    "gorm.io/gorm"
)

type User struct {
    *gorm.Model
    Name     string
    Email    string
    Password string
}
Enter fullscreen mode Exit fullscreen mode
  • Now run goose command to create migration file
mkdir migrations
goose -s create create_user
Enter fullscreen mode Exit fullscreen mode
  • After this, you'll have import errors. Let's fix this
go mod tidy
Enter fullscreen mode Exit fullscreen mode
  • Update the 00001_create_user.go file to have the following
package migrations

import (
    "app/database"
    "app/models"
    "context"
    "database/sql"

    "github.com/pressly/goose/v3"
)

func init() {
    goose.AddMigrationContext(upCreateUser, downCreateUser)
}

func upCreateUser(ctx context.Context, tx *sql.Tx) error {
    return database.DB_MIGRATOR.CreateTable(&models.User{})
}

func downCreateUser(ctx context.Context, tx *sql.Tx) error {
    return database.DB_MIGRATOR.DropTable(&models.User{})
}
Enter fullscreen mode Exit fullscreen mode

Bringing It All Together

  • Update the main.go file to have the following
package main

import (
    "app/database"
    _ "app/migrations" // This loads the migrations init functions

    "github.com/pressly/goose/v3"
)

func main() {
    err := database.ConnectToDatabase()
    if err != nil {
        panic(err)
    }

    if err := goose.SetDialect("postgres"); err != nil {
        panic(err)
    }
    if err := goose.Up(database.SQL_DB, "migrations"); err != nil {
        panic(err)
    }
    // Start server...
}
Enter fullscreen mode Exit fullscreen mode
  • Now you can run migrations before starting the server
go run .
Enter fullscreen mode Exit fullscreen mode

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

Top comments (1)

Collapse
 
__59cdb67 profile image

I got this error when running my main.go
failed to run Go migration: Go functions must be registered and built into a custom binary

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more