Every major web oriented backend programming language has at least a couple popular DB migrations frameworks. I have yet to use one that I liked. The whole point of these libraries is to save time and prevent mistakes. I feel like most of them have very successfully done the opposite.
The reasons I think many of these libraries and frameworks fall short boil down these bad assumptions (my opinion):
As an example, I spent several days troubleshooting a low-level bug in Liquibase. A fairly common scenario failed with no error messages or hints of any kind. I had to debug into their source code to find the issue. You could argue this type of thing doesn't happen that often, but one look at their github issues page says otherwise. I get that this is common for large popular projects. My point isn't that github issues equals bad code. My point is that some of these frameworks and libraries bite off more than they can chew. Not because they're not smart but because the problem they're trying to solve has too many possible combinations. It's really an entire language they've built on top of multiple other languages (multiple version of Java, XML, json, yaml, multiple database platforms).
My solution to this problem was to use the simplest possible built-in functionality to keep track of plain SQL scripts and simple Up/Down commands. I'm not the only one to come up with this solution. There are several small libraries that do something similar (keep track of the migrations but no extra translation layers). This repo is my attempt at an example of the minimal solution for the .NET platform.
You can see it being used in my dotnet-react-sandbox project. Check out the github repo for the proof of concept here: db-migrations-dotnet