A topic that keeps on coming up in
r/reddit is How do I solve database
migrations in Go ? Most people including myself came from other languages
such as PHP and Ruby where database migrations are a problem that have been
solved. Rails from the Ruby world and Laravel from the PHP world as an example.
But how do I replicate such functionality in Go ? Also considering the fact that
frameworks are an anti-pattern in Go.
In both Rails and Laravel for example, you run a command
php artisan migrate. It’d be fairly easy to run that command as a step in
your deployment pipeline but how can we replicate that functionality in a Go
To solve this problem in Go, a lot of libraries have been created but I have had the most success with the migrate library. I will be building a tiny application - only package main - that shows this process along with how you can build any Go web app with automatic database migration on it’s startup and how you can deal with some intrincasies as per deployment. I will also explain how this ends up in the real world.
A sample application
migrate library requires some convention as per the migration files. This
is expected as it is a matter of convention over configuration. The migration
files have to be named
basically, each migration should have an
down.sql file. The
up.sql file will be executed on actually running the migration while
down.sql will execute when a rollback is attempted.
You can use the migrate cli tool to create the migrations though.
migrate create -ext sql create_users_table
That above my friend is the easiest way to do database migration in Go. You can
go ahead to download the following files from this repo
and place them in the
directory or wherever you deem fit. After which you will need to run it with the
$ go run main.go -mysql.dsn "root:@tcp(localhost)/xyz"
If all goes well, you should see a “Database migrated” printed on standard output.
While this is ridicously easy to set up, it does bring a dependency on the filesystem - the migration files have to be present in order to for the migration to be possible. This is also easy to solve. There are 3 ways to solve this:
- If your application runs in a container, just mount the migration files into the image. Capice. Here is an example:
- If you have CI/CD processes in place, you can make use of the cli tool that
migrateships with. Just include it a step before the actual deployment process as you have the source to the files during the automated testing phase - at least if they are versioned, which they ideally should be. See its documentation.
I haven’t actually done this but it does look like a viable option.
- The last step is actually a work in progress but it depends on embedding the migration files into the binary. With that step, you actually destroy the dependency on the filesystem. There is an opened PR for that right now and I’d be keeping an eye opened to update this post should in case its status changes.
comments powered by Disqus
Update: this has become my most preffered method of doing this. Use
go-bindatato embed the files and capice