Skip to main content

Command Palette

Search for a command to run...

Scaling Flutter Codebases: Enforcing Rules Without Slowing Teams Down

Updated
5 min read
Scaling Flutter Codebases: Enforcing Rules Without Slowing Teams Down

Working in mid to large-sized teams often means everyone brings their own working style—code formatting preferences, commit message habits, naming conventions, and even different interpretations of language or framework best practices. This diversity works fine initially, but without enforced standards, it quickly turns into a serious problem.

Over time, lack of consistency slows everything down. Onboarding new developers takes longer than it should, moving code from development to production becomes frustrating, and the overall developer experience degrades—costing both productivity and money.

I’ve personally seen teams struggle with untraceable changes due to inconsistent commit messages, unnecessary merge conflicts caused by mismatched formatting, and blocked deployments because a single broken test brought the entire CI pipeline to a halt. Add to this the increased time from writing code to shipping it, and delayed timelines become inevitable.

But what if these issues could be prevented at the source? What if language, framework, and project-specific rules were enforced automatically—so code that didn’t meet the standards simply couldn’t be committed in the first place?

This is where Git hooks come into play.

Git hooks are configurable scripts that run at specific points in a code’s lifecycle—such as before a commit or before a push. They allow teams to automatically run checks and decide whether an action like a commit or push should succeed or fail, entirely based on predefined rules.

In this article, I’ll focus specifically on setting up a pre-commit hook for a Flutter project to enforce essential quality checks before any code is committed.

A commit will only succeed if:

  • There are no compilation or linting issues

  • The code is formatted according to Dart’s formatting guidelines

  • All tests pass successfully

  • Commit messages follow project-specific conventions

You can learn more about Git hooks and how to configure them here. (link)

Pre-Commit Workflow From a Developer’s Perspective

Setting Up the Pre-Commit Hook

Git hooks live inside the .git/hooks directory of a repository. These hooks are local to the developer’s machine, which means they don’t get committed to version control by default.

To start, navigate to your project root and create a pre-commit file:

cd .git/hooks
touch pre-commit
chmod +x pre-commit

This pre-commit file is the script Git will automatically execute every time a developer runs git commit.

If this script exits with a non-zero status code, the commit is rejected.

That’s the only rule you need to remember.

Writing the Pre-Commit Script

The script can be written in Bash (most common), and its responsibility is simple:
run checks → fail if something breaks.

Below is a basic but production-ready example for a Flutter project.

#!/bin/sh

echo "Running pre-commit checks..."

# 1. Static analysis
echo "Running flutter analyze..."
flutter analyze
if [ $? -ne 0 ]; then
  echo "❌ flutter analyze failed"
  exit 1
fi

# 2. Code formatting
echo "Checking code formatting..."
dart format --set-exit-if-changed .
if [ $? -ne 0 ]; then
  echo "❌ Code formatting issues found"
  echo "Run: dart format ."
  exit 1
fi

# 3. Tests
echo "Running tests..."
flutter test
if [ $? -ne 0 ]; then
  echo "❌ Tests failed"
  exit 1
fi

echo "✅ All pre-commit checks passed"
exit 0

At this point, you’ve already eliminated:

  • broken builds

  • inconsistent formatting

  • failing tests entering the repo

All before the code ever leaves a developer’s machine.

Enforcing Commit Message Conventions

Pre-commit hooks don’t receive the commit message by default.
For that, Git provides another hook called commit-msg.

Create it alongside pre-commit:

touch .git/hooks/commit-msg
chmod +x .git/hooks/commit-msg

Example commit-msg script:

#!/bin/sh

COMMIT_MSG_FILE=$1
COMMIT_MSG=$(cat "$COMMIT_MSG_FILE")

PATTERN="^(feat|fix|chore|docs|refactor|test): .{10,}"

if ! echo "$COMMIT_MSG" | grep -Eq "$PATTERN"; then
  echo "❌ Invalid commit message format"
  echo "Expected format:"
  echo "feat: short meaningful description"
  exit 1
fi

exit 0

Now:

  • commits without context

  • vague messages like fix, temp, wip

never make it into history.

Making This Work in Large Teams

One important thing to address:
.git/hooks is not shared by default.

In real teams, you’ll want to:

  • store these scripts in a versioned directory (e.g. scripts/git-hooks)

  • add a small setup script that copies them into .git/hooks and probably add it to the Makefile with a simple setup alias

  • document this as a mandatory onboarding step in the README

This keeps the rules consistent.

Why This Approach Scales

At scale, this setup does something very important:

  • Developers get instant feedback

  • CI pipelines stop failing for trivial reasons

  • Code reviews focus on logic, not hygiene

  • Teams stop arguing about formatting and conventions

  • New developers ramp up faster without memorizing rules

Most importantly, it removes humans from enforcing things that machines are better at enforcing.

Closing Thoughts

Pre-commit hooks are not about control or restriction.
They’re about protecting focus.

By enforcing basic quality checks at the earliest possible point, teams avoid unnecessary friction later in the development lifecycle. When done right, these hooks become invisible—developers don’t think about them, because things “just work”.

If you’re working with a growing Flutter codebase and struggling with consistency, start small:
add one check, let the team feel the benefit, and evolve from there.

This approach closely follows the principles from Extreme Programming Explained by Kent Beck—particularly fast feedback and building quality in from the start. Pre-commit hooks bring those ideas directly into the local development workflow, long before CI or code reviews come into play.