How to handle migrations in Golang
And important topics for any other language

Search for a command to run...
And important topics for any other language

No comments yet. Be the first to comment.
The only article that you need to convince your team and your boss

When working on interactive websites, we constantly face the challenge of defining if something should be executed on the server or in the client, but how do we decide it? This article will help you know how. This article does not applies to SPAs. ...

When I'm creating a new project, I always have the same problem: To follow best practices and make the code maintainable, the codebase becomes extremely verbose. It always takes my motivation from me to have to write a bunch of stuff only to make som...

Everyone sees the world through a unique lens, shaped by their own experiences and ideas. Recognizing this and being willing to listen to and understand different perspectives is essential for discovery, personal growth, and building better things to...

Yes, yet another tutorial

We always can create and run our migrations manually, but if we want to make it faster, safer, and easier to read and maintain, it's recommended to use a specialized tool for it.
To choose this tool, we need first to analyze what are the requirements for "handling migrations". They are:
UP and DOWN migrations to apply and revert the changesOn the next sections, let's dig up a bit about each one of these features, and at the end let's see some tools that we can use for it.
UP and DOWN migrationsGenerate migrations is not a requirement, but is a great bonus. It saves a lot of time and rarely needs any adjust. To do it, the tool needs to get the current state of the database, the new state that you want to apply and create the necessary SQL queries to synchronize both, in the best way possible and without any bugs.
The current new state that you want to apply can be defined as code or a specific schema file, but I'll talk more about it on the Know the current structure of your database chapter.
Up and Down migrations can be written in 2 ways:
.<your-language> files (in this case, .go)I personally prefer to have raw SQL files, because this way I fell safer that none of the behaviors of the language will affect my migration, and any of the updates in the language will make me update previous migrations.
If the tool doesn't generate the migrations for you, you will have to write them manually.
This is without a doubt the most important part of every migration tool. It's very important to know which migrations already were executed, so the tool can avoid running the same migration twice and causing an error.
For our luck, all the most famous tools for handling migrations do it very well.
This is the part that improves dev experience and the velocity that you can modify your database to fit your new needs. Have a simple and fast way to know the current state of your database is essential for many things: Have the big picture of your database, be sure how a change would affect it, if it has the best performance that it can have (with all the right indexes and relations), if it has a column that you need and how can you add it if necessary.
Most tools don't have a way to do it, and once you start using this kind of documentation, your life changes, and you never want to work with an undocumented database again.
There are ORMs like gorm that supports some kind of documentation with files, but they mainly focus on converting the database to "things" in the code to be used by the ORM, and not as documentation only/documentation-first.
To solve this problem, DBML was created, but it lacks a lot of features required for migration tools.
A basic Golang specific tool to run migrations.
Pros:
Cons:
Another Golang specific tool to run migrations, with a bit more functionalities.
Pros:
Cons:
A language agnostic tool to run migrations.
Pros:
Cons:
A wrapper to a JavaScript library that is both an ORM and a migration management tool.
Pros:
Cons:
Both golang-migrate and goose can't generate migrations and don't have a way to document your database, so I can exclude them already.
Atlas has a lot of potential, has the core that we need: From a schema file it can generate things. Generate migrations, .dbml files or "things" specific for your code to be used by an ORM if you want to.
The only problem with Atlas is that I personally hate HCL for databases, I think that it's overcomplicating the problem, too many keywords words for something simple. I know that it decreases development complexity for the guys maintaining it, but it's a terrible experience for anyone using it.
If you like HCL, I recommend you to go with Atlas. It may be risk because it's maintained by a small company, but I think that it's the best option that we have in the market.
And last: Go prisma. I use it, not because I think it's a great tool, has the best performance or has extra unseen magical features. I use it because prisma.schema.
The Prisma syntax for writing database specifications is good, not the best, may be a little overdecorated, but works, it's simple, it's understandable and has its own formatter (HCL also has one btw). Go Prisma is a workaround to use Prisma without having to install it using node, and to be honest, at this moment, I'm not even sure if you can run it without having node installed.
I prefer to take the risk and have some other things installed to be able to use the prisma.schema file, since at the moment (and for the next years) it will not affect significantly my project.
Hope that you liked the article, and please feel free to share your options on the comments!