Skip to content
➜cat blog/freelance-to-product-lessons.md

From Freelance to Product: Lessons Shipping Client Projects

What 10+ client projects taught me about scope, estimation, client communication, and knowing when to push back.

7 min

I've worked on over ten client projects across two agencies and freelance work. Web applications, marketing sites, dashboards, e-commerce platforms. Each one taught me something that no tutorial covers. These are the lessons that changed how I work.

Estimation Is a Skill, Not a Guess

Early in my career, I estimated based on how long the code would take to write. A login page? Maybe a day. A dashboard? A week. These estimates were consistently wrong because they only accounted for the writing.

What they missed:

  • Understanding requirements: reading specs, asking questions, getting clarity on ambiguous features
  • Design implementation: translating Figma to code is rarely one-to-one; there are always gaps and edge cases the designer didn't consider
  • Testing: not just unit tests, but manual testing, cross-browser testing, responsive testing
  • Revisions: the client will have feedback, always
  • Integration: connecting to APIs, handling loading states, error states, empty states
  • Deployment: CI/CD setup, environment configuration, DNS, SSL

Now I estimate the coding time and multiply by 2.5. A login page that takes 4 hours to code takes 10 hours to ship. This includes all the non-coding work that makes the code actually useful.

Scope Creep Has a Mechanism

Scope creep doesn't happen because clients are unreasonable. It happens because requirements are discovered, not defined. The client says "we need a contact form" and means a form with name, email, and message. Two weeks later, they realize they also need file attachments, department routing, auto-responses, and a CRM integration.

These aren't unreasonable requests. They're requirements that emerged as the project took shape.

The defense:

  1. Write everything down. Before starting, document every feature in enough detail that both parties agree on what "done" means. "Contact form" is too vague. "Contact form with name, email, message fields; validation; email notification to admin" is specific enough to scope.
  2. Change requests are normal. When new requirements emerge, acknowledge them and frame the impact: "Adding file attachments is possible. It'll take an additional three days and requires setting up file storage. Want to include it in this phase or add it to a follow-up?"
  3. Phase the work. Large projects should have milestones with deliverables. Phase 1: core features. Phase 2: enhancements. This gives the client flexibility to adjust priorities without blowing up the timeline.

Client Communication Patterns

Weekly updates, not daily. A brief email or message every Monday summarizing: what was completed last week, what's planned this week, any blockers or decisions needed. Daily updates are noise for most clients.

Show, don't describe. Instead of "I implemented the filter functionality," send a 30-second screen recording showing the filter in action. Clients understand demos better than descriptions.

Bad news early. If something is going to take longer than estimated, say so immediately. Not when the deadline arrives. "The payment integration is more complex than expected, and I need three extra days" is a conversation. "I missed the deadline" is a problem.

Ask, don't assume. When a requirement is ambiguous, asking takes five minutes. Assuming takes days of rework when you guess wrong.

When to Push Back

Clients hire you for your expertise, not just your ability to translate Figma to code. Pushing back respectfully is part of the value you provide.

Push back when the request would create technical debt that the client will pay for later. "We can add this feature without authentication now, but adding authentication later will require rewriting the entire data layer. Building it correctly now adds two days."

Push back when the timeline is unrealistic. "Shipping all five features by Friday means skipping testing. I'd recommend shipping three features with proper testing and delivering the remaining two next week."

Push back when the design has UX problems. "This form has twelve fields on one page. Splitting it into three steps would significantly improve completion rates. I can implement both approaches and let user data decide."

Don't push back on preferences. If the client wants the button blue instead of green, make it blue. Not every hill is worth dying on.

The Freelance-to-Product Shift

Working on my own product (this portfolio, internal tools) after years of client work felt different in one key way: there's no external deadline forcing decisions.

In client work, the deadline is a forcing function. You can't deliberate indefinitely. The budget runs out, the launch date arrives, and you ship what you have. This is actually healthy. It forces prioritization.

On personal projects, the absence of a deadline leads to endless polishing. I've learned to set artificial deadlines for personal work and treat them with the same seriousness as client deadlines. "This portfolio ships by March 1" is a commitment, not a suggestion.

What Ten Projects Taught Me

  1. The code is 40% of the work. Communication, testing, deployment, and revision are the other 60%.
  2. Simple solutions survive. The clever approach breaks when requirements change. The straightforward approach adapts.
  3. Relationships matter more than code quality. A client who trusts you will forgive a bug. A client who doesn't trust you will scrutinize every pixel.
  4. Every project teaches one new thing. Actively look for it. On one project it was payment integration. On another, it was internationalization. On another, it was leading a team. The technical skills compound.
  5. Charge for your experience, not your time. A senior developer who finishes in two days has provided more value than a junior who takes two weeks. Price accordingly.