← All posts

7 min read

Documenting a Flutter Project for Handover: What to Write Down

How to document a Flutter project for handover: a README with FVM and flavors, an architecture map, a credential inventory, release runbooks, ADRs and a video.

  • Flutter
  • Documentation
  • Handover
Cover illustration for Documenting a Flutter Project for Handover: What to Write Down

The real test of a project isn’t whether it builds on your machine. It’s whether someone else can build it on theirs, six months after you’ve moved on, without messaging you.

I’ve been on both sides of this. I’ve handed projects over to clients and their next developers, and I’ve taken over existing Flutter apps where the only documentation was a default README that said “A new Flutter project.” The difference between those two experiences is usually a few hours of writing.

This post walks through what I put in a handover package, in the order I’d write it. It’s useful for developers, and it’s just as useful for founders who want to know what to ask for at the end of a project.

Start with the README

The README is the front door. Its job is to get a new developer from git clone to a running app in under an hour. Here’s the skeleton I use:

# Project Name

One paragraph: what the app does and who uses it.

## Requirements
- Flutter version: see `.fvmrc` (managed with FVM)
- Xcode / Android Studio versions known to work
- Access needed: Firebase project, App Store Connect, Play Console

## Setup
1. Install FVM, then run `fvm install`
2. Copy `config/dev.example.json` to `config/dev.json` and fill in values
   (ask the project owner for them; never commit this file)
3. `fvm flutter pub get`

## Running
fvm flutter run --flavor dev --dart-define-from-file=config/dev.json

## Testing
fvm flutter test

## Releasing
See docs/runbooks/release.md

## Architecture
See docs/architecture.md

A few details make a big difference here.

Pin the Flutter version. “Works with Flutter” is not a version. I use FVM so the exact Flutter SDK is pinned in a .fvmrc file in the repo. A new developer runs fvm install and gets the same SDK the app was built with. This one file prevents a whole category of “it doesn’t compile” messages, and it makes future upgrades a deliberate step instead of an accident.

Explain the flavors and environments. If the app has dev, staging and production builds, say which command builds which, which backend each one talks to and where its config lives. Commit an example config with fake values so people know the shape:

{
  "API_BASE_URL": "https://api.dev.example.com",
  "SENTRY_DSN": "",
  "MAPS_API_KEY": "replace-me"
}

I go deeper on the setup itself in Flutter flavors for dev, staging and production.

Test the instructions. Clone the repo into a fresh folder and follow your own README word for word. Every step you have to improvise is a missing line.

Write a short architecture overview

New developers don’t need a 40-page design document. They need a map. My docs/architecture.md usually fits on two screens and answers:

  • How the code is organized. Feature folders or layers, and where a new screen should go.
  • State management. Which approach, and the one or two conventions everyone must follow.
  • Data flow. How a screen gets data: widget, state, repository, API client. One diagram helps here, even a hand-drawn one.
  • The backend. What the app talks to, where it’s hosted and where its code lives.
  • Third-party services. Payments, push, analytics, crash reporting, maps. One line each.
  • The weird parts. Every project has them: a native plugin, a workaround for a platform bug, a screen that’s slow for a known reason. Write them down with the reason. Otherwise the next developer “fixes” them.

That last section is the most valuable one, and the one most often skipped.

Build a credential and account inventory

This is the part founders care about most, and it’s often where handovers go wrong. Apps depend on a surprising number of accounts: app stores, Firebase, cloud hosting, payment providers, email services, domains, analytics.

The inventory lists what exists, where it lives and who owns it. It does not contain the secrets themselves. Those belong in a password manager that the client controls, never in the repo and never in the README.

Item Where it lives Owner Notes
Apple Developer account Client’s Apple ID Client Developer has App Manager role
Google Play Console Client’s Google account Client Developer invited as user
Android upload keystore Password manager + CI secrets Client Losing it means a key reset request
Firebase project Client’s Google account Client Prod and dev are separate projects
Payment provider Client’s account Client Live keys only in backend config
Backend hosting Client’s cloud subscription Client Billing alerts set

Notice the pattern in the Owner column. As a rule, the client should own every account, and the developer should be an invited member. If the developer leaves, the client removes their access and nothing breaks. If the accounts belong to the developer, a handover turns into a migration project. If you’re a founder, insist on this from day one; it’s one of the points in working with a remote freelance developer.

At handover, I go through the table with the client, confirm they can log in to each item themselves, and then remove my own access where appropriate.

Write runbooks for the things that happen again

A runbook is a step-by-step checklist for a task that happens occasionally, so occasionally that nobody remembers how. For a mobile app, the essential ones are:

  • Releasing a new version. Bump the version and build number, build each platform, upload, fill in release notes, submit for review, tag the commit. Include where the signing files come from.
  • Rotating a key or certificate. Push certificates, API keys, signing credentials. What to change, where, and how to verify it worked.
  • Common issues. “iOS build fails after Xcode update: run this.” “Push notifications stopped: check this first.” Each entry is a symptom, the likely cause and the fix.
  • Restoring service. If the backend goes down, where to look, how to restart it, who to contact.

I write runbooks as numbered steps with the exact commands, because they’re used under pressure. “Deploy the backend” isn’t a step. The command to deploy the backend is.

Record decisions as ADRs

Code shows what was built. It rarely shows why. Architecture Decision Records fill that gap. Each one is a short Markdown file in docs/decisions/:

# 0004: Use Drift for local storage

Date: 2026-01-01
Status: Accepted

## Context
The app needs offline access to job records with filtering and sorting.

## Decision
Use Drift (SQLite) instead of a key-value store.

## Consequences
Typed queries and migrations. Adds code generation to the build.

They take ten minutes to write. Months later, when someone asks “why didn’t we just use Hive here?”, the answer is already written down, along with what the trade-off was. ADRs also stop the next developer from reversing a decision without knowing what problem it solved.

Record a short walkthrough video

Documents are great, but some things are faster to show. I record a short screen-share walkthrough, usually split into a few short clips:

  1. The app as a user sees it. The main flows, each role, the admin side if there is one.
  2. The codebase tour. Folder structure, one feature traced from screen to API, where the tricky parts are.
  3. A release, start to finish. Or at least the parts that aren’t obvious from the runbook.

It doesn’t need editing or a script. Talking through the code while showing it captures context you’d never think to write down. Link the videos from the README so they’re found.

When to write all this

Not at the end. A handover package written in the final week is rushed and incomplete. I keep the README and runbooks current as I go, write ADRs when decisions happen and do the inventory and video near the end. Then the final handover is a review, not a writing marathon. It also helps a lot with maintaining the app after launch, even if nobody new ever joins.

Takeaways

  • The README should get a new developer from clone to running app, with a pinned Flutter version and clear flavor setup.
  • A short architecture overview that explains the weird parts beats a long design document.
  • Keep an inventory of accounts and where credentials live, with the client owning everything, and keep secrets out of the repo.
  • Write runbooks with exact commands for releases, key rotation and common issues.
  • Use ADRs to record why decisions were made.
  • A rough walkthrough video captures context documents miss.

Good documentation is the last feature you ship, and the one that decides whether the others keep working.

Comments

Questions, corrections or your own experience — leave a comment below (GitHub sign-in).