A database changes constantly over the life of a project. A new column, an extra table, an index, a rename. Apply changes like these by hand on every system and development, test and production drift apart sooner or later. And then nobody knows which state applies where.
A migration is a small file describing exactly one change step, along with the way back. It sits in the same repository as the code and is versioned with it. One command applies every step not yet applied, in the right order.
Why this matters more than it sounds
The real value is in being able to trace things. Any environment state can be reproduced from the repository. A new developer has a working database after two commands. A deployment brings the matching structural changes with it by itself.
One rule has proved itself. A migration that has already run on the production system is not changed again. Whatever is still missing follows as a new migration. Otherwise the states stop matching.