← All posts

6 min read

Working With a Remote Freelance Developer: How to Make It Work

How to work with a remote freelance developer: time-zone overlap, async updates, written acceptance criteria, weekly test builds, owning your accounts and clean handover.

  • Freelancing
  • Remote Work
  • Collaboration
Cover illustration for Working With a Remote Freelance Developer: How to Make It Work

I live in Sylhet, Bangladesh. Most of my clients don’t. When they’re starting their workday, I’m often wrapping up mine, and when they send a message late at night, it lands in my morning.

I’ve freelanced on Upwork since 2021, and before that I started my own studio, Crazybot Studio. Over those years I’ve learned that distance is rarely what makes a remote project go wrong. What goes wrong is unclear expectations, which distance just makes harder to notice.

This post is for clients who are about to hire a remote developer, or already have one and feel slightly out of the loop. It’s the setup I ask for on my own projects, written from the developer’s side of the call.

Time zones are a feature if you plan for them

A big time difference sounds like a problem. It can actually be useful: you send feedback at the end of your day, and the fix is waiting when you wake up.

That only works with two things in place.

A small overlap window. An hour or two where both people are online, a few days a week, is enough for most projects. That’s when we do calls, demos and quick back-and-forth decisions. I’m happy to shift my hours to make the overlap work; most remote developers who’ve done this a while are.

Async by default. Everything that doesn’t need a live conversation goes in writing: a project board, a shared doc or a single chat channel. Not five channels. One place where decisions live, so nobody has to search their email, WhatsApp and Slack to find out what was agreed.

The useful habit is writing messages that don’t need a reply to be understood. “The login screen is done; I couldn’t test Apple sign-in because the account isn’t set up yet. Can you add me to the developer team?” beats “Quick question, got a minute?” every time.

Write it down: specs and acceptance criteria

A spec doesn’t have to be long. It has to be specific enough that we both agree what “done” means before I start.

For each feature, I like to have:

  • What the user does, step by step, in plain language.
  • What they see when it works, and when it doesn’t (no internet, wrong password, empty list).
  • Acceptance criteria: a short checklist you’ll use to say yes, this is finished.

For example, acceptance criteria for a password reset feature might be:

  • User can request a reset from the login screen by entering their email.
  • They see the same confirmation message whether or not the email exists.
  • The reset link opens the app if it’s installed.
  • After resetting, they’re signed in and land on the home screen.

That’s four lines, and it removes most of the “I thought it would…” conversations later. If you’re not sure how to write these, a good developer will draft them with you. I usually do, then ask the client to correct me.

See a working build every week

Status messages are nice. A build you can install is better.

On my projects, the client gets a new build regularly, usually weekly:

  • iOS through TestFlight, Apple’s beta testing service.
  • Android through Google Play’s internal testing track.

You install it like a normal app, tap around, and send feedback. No screenshots, no “trust me, it’s nearly done.” If something feels off, you find out in week three instead of week twelve.

This works best with automated builds, so producing a test build doesn’t eat half a day. I’ve written about setting that up in Flutter CI/CD with Azure DevOps.

A short recorded video walkthrough alongside the build helps too, especially for features that are hard to reach or need a specific test account.

Own your accounts, repos and keys

This is the part I’m most insistent about, and it’s the one clients most often skip because it feels like admin.

You, the client, should own:

  • The Apple Developer account and the Google Play Console account, registered to your business.
  • The code repository (GitHub, Azure DevOps, GitLab), under your organization. The developer gets access; they don’t own it.
  • Cloud and backend accounts: Firebase, Azure, AWS, your database host.
  • Third-party services: Stripe, RevenueCat, maps, email, analytics.
  • Signing keys and credentials, stored somewhere you control, like a password manager shared with the developer.
  • The domain and any email used to register services.

The developer gets invited with the access they need. When the project ends, you remove that access, and nothing breaks.

I’m saying this as a developer because the opposite situation hurts clients badly. I’ve been asked to help with apps where the previous developer published under their own account, kept the code on their laptop, or held the only copy of the Android upload key. Getting out of that is slow and sometimes not fully possible. More on this in hiring a Flutter developer: what to look for.

Milestones that end in something real

Break the project into milestones where each one ends in a build you can test against written acceptance criteria. For a typical app, something like:

  1. Sign-in and the main screen with real data
  2. The core flow (booking, ordering, logging, whatever the app is for)
  3. Payments or subscriptions
  4. Notifications, settings and polish
  5. Store submission and launch

On Upwork, milestones map neatly to how payments are released. Even outside Upwork, the structure helps both sides: you pay for finished, testable work, and the developer knows exactly what “finished” means.

When new ideas come up mid-milestone, and they will, write them down and decide together whether they go into this milestone, a later one, or the “after launch” list. Silent scope creep is how good relationships go sour.

Handover documentation

Even if you plan to work with the same developer for years, ask for handover docs. Developers get busy, teams grow, and the next person should be able to start without archaeology.

A useful handover covers:

  • How to run the project locally, step by step
  • Where every account and credential lives (not the secrets themselves in the doc)
  • How builds and releases work
  • The architecture in one page: main folders, state management, how the app talks to the backend
  • Known issues and decisions that look odd but were made on purpose
  • Upcoming deadlines: certificate expiries, store SDK requirements

I write this as the project goes, not at the end. Writing it at the end means half of it is forgotten.

A few habits that make it smoother

  • Give one person the final say on product decisions. A developer getting different answers from two co-founders is stuck.
  • Respond to blocking questions quickly, even with “I’ll check and get back to you tomorrow.”
  • Test the builds you’re sent. Feedback that arrives two milestones later is much more expensive to act on.
  • Say what’s bothering you early. Small concerns are easy to fix in week two.

Takeaways

  • Plan a short daily or weekly overlap window and handle everything else asynchronously, in one place.
  • Write acceptance criteria for each feature so “done” means the same thing to both of you.
  • Expect a working build regularly through TestFlight and Play internal testing.
  • Own your developer accounts, repositories, cloud services and keys from day one.
  • Use milestones that end in testable builds, and handle new ideas deliberately.
  • Ask for handover documentation that’s written as the project goes.

If you’re looking for a remote Flutter developer who works this way, tell me about your project.

Comments

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