Photo by Joshua Woroniecki on Unsplash

Django tricks: how to guarantee migration files are always up to date

Adrien Van Thong
2 min readNov 17, 2023


Have you ever made some slight innocuous changes to you Django models, and later (sometimes, much later) found out those changes resulted in migration files that were never created? Like fixing a typo in a field’s help_text? This simple mistake can happen to just about anyone, even the most seasoned Django veterans.

In this article I’ll go over a quick and easy way to help keep ourselves accountable by creating a mechanism for automated feedback when we forget to run the makemigrations command before checking in our code.

For this article, I’ll assume we’re using a simple bash script executed from Jenkins, but this concept can be adapted for any CI/CD platform.

Enforce via CI/CD

As with most Django app developers, our CI/CD pipeline runs an exhaustive suite of unit tests to help catch any potential regressions. Unfortunately these unit tests may not catch any missing migration files, depending on the change. To catch this, we have separate step in our pipeline which executes a bash script which will run the makemigrations command to validate that no migrations need to be run. We pass in both the --check and --dry-run options so that, in the event there is in fact a missing migration, it doesn’t impact the files on the system.

If the command returns a non-zero exit code, the script will error out and fail the build.

Example below:

# Check to make sure we have no missing migrations
if ! python $APP_PATH/ makemigrations --check --dry-run; then
printf "Error: makemigrations check failed! Failing build!\n"
return 1

Adding this small check to our CI/CD builds has been great for avoiding these honest mistakes — let’s face it, it’s not always to remember every change which results in a new migration file being created!

Ever since adding this script to our builds, we can guarantee with 100% certainty that the code running in production (or dev, whichever the case may be) is always up-to-date on its migration files.

Do you have any other tricks to help catch human errors in your Django apps? Sound off in the comments below!