Dart code generation files in git. Yes or no?
I started writing Flutter and Dart code a few weeks ago for a real production project that we are migrating from another tech stack (Xamarin).
Soon I started using the power of code generation libraries like freezed, json_serializable, slang_build_runner and others. These libraries usually work with attributes in your class or methods, or by transforming existing metadata files into more useful stuff.
The build_runner package will be in charge of generating all the code for you. I learned this is a very common pattern and practice in the Dart world and hard to avoid if you value your time.
Have you wondered if those files should go into the git repository or not?
I asked myself that question. Searching some people's opinions online I saw there are different points of view on the subject so I needed to figure it out internally on my team.
Next, let's explore reasons to include or exclude those files 👇.
The main reasons to include code generation files
If the files are not included, your app will not build correctly whenever you:
clone the project
git clean -xdf
other cleaning scenarios
It's inconvenient to manually run commands or tasks to generate all files every time.
I heard some people saying that code generation can differ from one machine to another. For instance: your local machine vs a CI server machine. However, I guess this can be done right by taking good care of dependency versions.
Reasons to exclude code generation files
Let's assume you work in a team environment where Pull Requests and code reviews are common practice. The list of files to review will increase significantly when all the generated files are there, making it harder for your teammates (we can learn to ignore them but it requires an extra effort that might not be worth it).
Besides that, you will be polluting your git repository with unnecessary trash that eventually will increase the size big time. It might not look like a problem now, but your build pipeline will suffer in the long term.
If you work alone in small projects though, those files should not be a problem.
Guess what? we chose to exclude the files
But then we needed to fix the problems mentioned above.
It became easy with a couple of workarounds.
The first thing to notice is that watching files to re-generate the code is as simple as running this command line:
flutter pub run build_runner watch --delete-conflicting-outputs
If you feel too lazy to mess with your terminal you might like this VSCode extension which does the same with a click of a button.
But that didn't always work for me.
If someone added a new dart package to Pubspec we had to run
dart pub get.
The library we use for translations (slang) requires an additional command to convert JSON files into dart code:
dart run slang.
And who knows what we'll need in the future?
Simple solution: automate the boring stuff
Simple as a git post-checkout script.
You can tell Git to run any command(s) you like when switching branches.
Here's how to:
Create a file
post-checkout (without extension) at:
[Project root]/.git/hooks/ directory.
Your system may be hiding the
.git directory, but this can be done easily with your command line:
cd your project
touch .git/hooks/post-checkout # creates the file
chmod -x .git/hooks/post-checkout # give it execute permissions
code .git/hooks/post-checkout # open the file with vscode for edit
At this point, you can add any commands to the file. This is my current setup:
# 👆this line here is important!
# restore packages
dart pub get
# generate translations
dart run slang
# library code generation
dart run build_runner build --delete-conflicting-outputs
And now I can happily switch to any branch of the project and everything will just work.
The only downside now is that switching branches will take longer than expected.
If you like this solution and want to share it with the team, beware that
git hooks cannot be shared through git (as with any other file inside
.git/) so your teammates won't see it. Instead, you can instruct them how to set it up or just add this information to the project's README as I did.
There is a workaround though, but that goes beyond the scope of this post. Here's a blog explaining it.