Every Flutter developer has faced this problem:
You add a new field to your database, then you need to update your API, then your Flutter models, and finally your UI. Somewhere in that process, you forget a type, mistype a key, or miss a migration. Suddenly, your app compiles but crashes at runtime.
This happens because we lack a single source of truth. Our app and our database often live in separate worlds, and we’re the bridge that constantly tries to keep them aligned.
But what if we could remove that friction? What if the database schema itself could generate our app code? That’s the power of code generation.
The Pain: Duplication Everywhere
When working on apps, I kept running into the same issues:
- I had to duplicate code between backend and frontend.
- A schema change meant manual updates in multiple places.
- There was no single source of truth.
It felt like I was solving the same problem twice (or more).
The Idea: A Single Source of Truth
Instead of duplicating models, we define our schema once and let tools generate code for us. That way:
- The database schema drives the app models.
- Any change propagates automatically.
- The risk of “out of sync” disappears.
Depending on your database, the approach changes a little.
Firestore + Protobuf
Firestore is flexible but also risky: it doesn’t enforce schemas. That’s great for prototyping, but in production you need structure.
This is where Protobuf (Protocol Buffers) comes in:
- You define your models in
.proto
files. - Protobuf generates code automatically for Dart and also for TypeScript (and other languages).
- This means you can use the same models in your Flutter app and in your backend (e.g., Cloud Functions or any Node.js service).
- Serialization is efficient — smaller and faster than JSON.
Example schema:
From this .proto
you can generate:
- In Dart (for your Flutter app):
- In TypeScript (for Cloud Functions or backend):
This way, your frontend and backend share the same contract: no duplicated models, and any schema change propagates automatically.
Postgres + pg_graphql + Ferry
If you’re in the SQL world, things get even better. Postgres has a hidden gem: pg_graphql, an extension that turns your tables into a GraphQL API instantly.
Here’s how the flow looks:
- You define your schema in Postgres (tables, relations, constraints).
pg_graphql
exposes that schema as a GraphQL endpoint.- In Flutter, you use Ferry, a GraphQL client with code generation.
Example query:
Ferry generates Dart code for that query. Then, in Flutter, you just do:
No manual mapping. No fragile strings. If your schema changes, your Flutter code won’t even compile until you update it. That’s type safety at its best.
The Bonus: Caching & Performance
Another advantage of this setup: once your schema drives your client, you also get query optimization and caching for free.
- Ferry normalizes your GraphQL responses.
- Supabase (or raw Postgres) handles efficient queries.
- Your app stays fast and consistent without extra effort.
Wrapping Up
Whether you’re on Firestore or Postgres, the principle is the same:
- Define your schema once.
- Generate your app code automatically.
- Stop duplicating logic.
For Firestore → use Protobuf.
For SQL (Postgres) → use pg_graphql + Ferry.
The result? A faster development cycle, fewer bugs, and a database and app that never fall out of sync.
At the end of the day, code generation isn’t about fancy tooling — it’s about freeing you from boilerplate so you can focus on building real features.
If you want to see more details about this topic, you can see my talk in FlutterConfLatam 2025 in this link:
Final Thoughts
Code generation is more than a productivity boost, it’s a mindset shift. By turning your schema into the single source of truth, you eliminate repetitive work, reduce errors, and speed up delivery. At Somnio, we’ve seen how these practices help teams ship faster and focus on what really matters: creating meaningful products. If you’re curious about applying this approach in your own projects, let’s connect and explore how we can bring your ideas to life.