.../articles/
GAE/Go + Database Migration

GAE/Go + Database Migration

2019.08.11

When developing an API, it's common to use an RDB (relational database) like MySQL or PostgreSQL as the data store.

Some frameworks come with convenient migration tools for editing an RDB schema, and since I personally got into application development through Ruby on Rails, I've used what was given to me without thinking too deeply about it.

However, in situations where you're developing with a variety of technology stacks, it's not uncommon to find that a Rails-like migration tool simply isn't available.

Here, I've thought through how to operate database migrations when using GAE/Go with PostgreSQL as the data store.


When deciding on the operational approach for database migrations, I selected and set up a tool while considering the following points:

  • The basic operations needed for migration should be simple
  • I'm not particular about how migrations are written
  • I want the schema to be applied automatically at deploy time

With that in mind, the tool I decided to use is:

I won't go into detail on how to use sql-migrate here, since it's covered in the README and there are articles introducing it in Japanese as well, but I've set up migration tasks in a Makefile to bundle the commands I want to run before and after migration (I plan to write about this in a separate article).


Migration steps

Migrating in the local environment

The way sql-migrate is used is simple enough that it hardly needs explaining, but basically, you run it in the local environment following this flow:

  • new: generate a new migration file
  • up: apply the migration
  • down: roll back the migration

If you've written the migration file correctly, the schema should be updated as soon as you run sql-migrate up.

Applying migrations at deploy time

What should you do after applying migrations in the local environment? As an example, let's consider the case of using PostgreSQL set up on Cloud SQL from a GAE/Go server.

This is also covered in the README, but I'll introduce it as a concrete example with an excerpt of the code.

FileMigrationSource specifies the location of the migration files. I manage mine under app/db/migrations, so I've specified that with Dir. (I'm using sqlx to connect to the database.)

package db

import (
	"github.com/jmoiron/sqlx"
	migrate "github.com/rubenv/sql-migrate"
)

var (
	migrations = &migrate.FileMigrationSource{
		Dir: "app/db/migrations",
	}
)

func ExecMigrations(postgresURL string) error {
	pg, err := sqlx.Connect("postgres", postgresURL)
	if err != nil {
		return err
	}
	defer pg.Close()

	appliedCount, err := migrate.Exec(pg.DB, sqlDriver, migrations, migrate.Up)
	if err != nil {
		return err
	}
	log.Printf("Applied %v migrations", appliedCount)
	return nil
}

ExecMigration is a function for applying migrations, and calling it from main runs the migration at startup. Whether to run the migration or not is probably best controlled via an environment variable or similar.

package main

func main() {
	// Flag for whether to apply migrations at startup
	if applyMigration == True {
		err := db.ExecMigrations(postgresURL)
		if err != nil {
			log.Fatal(err)
		}
	}
	// omitted
}

It's not much code, but this alone is enough to update the PostgreSQL schema at the same time as deploying to GAE. If the migration ran successfully, you should see "Applied x migrations" in the logs.

sql-migrate is a simple, easy-to-use tool that isn't limited to Golang, so it seems like it could be useful when developing with other technology stacks as well.

written by

.../article/

Articles

All articles

From Firebase to Vercel, Contentful to microCMS — a migration log written with Claude Code

From Firebase to Vercel, Contentful to microCMS — a migration log written with Claude Code

We moved our corporate site's hosting and CMS, and made it bilingual along the way. The constraints we only found by running against real data were more useful than the migration itself, so this post focuses on where we got stuck.

Can't Read POST Data with Firebase Functions × Remix?

Can't Read POST Data with Firebase Functions × Remix?

How to read POST data from a Remix action when running on Firebase Functions.

Generative AI for Executives and Leaders: An Approach to Self-Driven DX

Generative AI for Executives and Leaders: An Approach to Self-Driven DX

Building a structure where executives and leaders themselves can identify issues and evaluate solutions using generative AI. We introduce how combining this with our hands-on support dramatically improves both the quality and speed of digital transformation.

Deploying a Monorepo Next.js App (App Router) to AWS Amplify

Deploying a Monorepo Next.js App (App Router) to AWS Amplify

Notes on the obstacles we hit while deploying a Next.js app managed in a monorepo to AWS Amplify.

Keeping Production Running Smoothly with Remote Work and Online Meetings [Documentation]

Keeping Production Running Smoothly with Remote Work and Online Meetings [Documentation]

Many production companies have adopted remote work as a result of the pandemic, and we are one of them.

Designing an E-Commerce Site That Sells: How to Find Great Reference Examples

Designing an E-Commerce Site That Sells: How to Find Great Reference Examples

There is no single formula for e-commerce design that sells. Driving revenue requires a solid concept, and getting to that concept requires thorough research.

Productivity Tools We Recommend as a Production Company, Including Services That Work Well Solo

Productivity Tools We Recommend as a Production Company, Including Services That Work Well Solo

With remote work becoming the norm during the COVID-19 pandemic, our team now works from home most days of the week.

We Released Thought Recorder, a Figma Plugin for Keeping a Commit History of Your Designs

We Released Thought Recorder, a Figma Plugin for Keeping a Commit History of Your Designs

We hope this helps web designers who work in Figma. Read on for how to use it.

How to Build an E-Commerce Site, and Which Platforms We Recommend

How to Build an E-Commerce Site, and Which Platforms We Recommend

Shopping online for fashion, appliances, and even groceries is now routine. With the pandemic accelerating the shift, we receive a steady stream of questions about which platform to use and how much it costs.

Generating FastAPI Schema Classes from OpenAPI

Generating FastAPI Schema Classes from OpenAPI

We chose FastAPI, a relatively modern framework, for a Python API project. FastAPI can generate an OpenAPI definition from your backend code, but here we do the opposite: generating FastAPI schema classes from an OpenAPI definition prepared in advance.

View all articles

Contact us