How I Scope Infrastructure Contracts Without Underbidding Myself
Statement of work templates, discovery calls, and estimate buffers — what I learned after a migration project ran 40% over the hours I quoted.

How I Scope Infrastructure Contracts Without Underbidding Myself
The first infrastructure contract I scoped badly was a Kubernetes migration for a Series A startup. I quoted 80 hours based on a clean architecture diagram they sent and a thirty-minute discovery call. The diagram omitted their legacy cron jobs, the Helm chart someone had forked three years ago, and the fact that their staging environment hadn't been updated since 2022. The project took 112 hours. I ate most of the overage because I hadn't written a statement of work tight enough to renegotiate when reality diverged from the diagram.
I still take migration work. I scope it differently now.
Scoping is not paperwork — it's how you protect both your margin and your relationship with the client. Under-scope and you resent the work; over-scope and you lose the bid. The goal is to be specific enough that surprises are visible early, and padded enough that normal surprises don't destroy you.
What Goes in the SOW Before You Quote Hours
I use a one-page statement of work for engagements under roughly 120 hours, and a longer appendix for larger ones. Every SOW I send includes these sections:
Objective — one paragraph on what "done" looks like from the client's perspective, not from yours. "EKS cluster running production workloads with CI/CD from GitHub Actions" is better than "Kubernetes setup."
In scope — enumerated deliverables. Cluster provisioning, IAM roles, baseline monitoring, runbook for rollback. Each item is a line, not a paragraph.
Explicitly out of scope — this section saved me twice last year. Examples I list routinely: application code changes, data migration, 24/7 on-call after handoff, training beyond two recorded walkthroughs, compliance audits (SOC 2 evidence collection), multi-region DR unless priced separately.
Assumptions — what must be true for the estimate to hold. Client provides AWS admin access within 48 hours. Existing Terraform is in a single repo they control. Staging mirrors production topology. No net-new third-party integrations.
Discovery cap — I bill the first 4–8 hours as paid discovery if the environment is unknown. That time produces the revised estimate. Clients who push back on paid discovery are often the same clients who hide complexity until week three.
Change process — how scope additions are handled. My default: written change request, revised hour estimate, client approval before work continues. No approval means I pause, not absorb.
I send the SOW before the hour estimate, not after. The estimate attaches to the SOW as an appendix. That order matters psychologically: they agree to boundaries first, then see the number.
Discovery: The Calls That Actually Reduce Risk
A discovery call is not a sales pitch. I run mine with a shared doc and a checklist. I ask to be screen-shared into the AWS console (read-only is fine) or their IaC repo before I quote fixed hours.
Questions I never skip:
- What broke last time you changed infrastructure?
- Who approves production changes, and how long does that take?
- Is there documentation you trust, and when was it last updated?
- What are you not telling me because you think it's embarrassing? (I phrase this more gently, but the intent is the same.)
I time-box discovery notes: current state, target state, risks, open questions. Those notes become appendix A of the SOW. If the client later says "we didn't know about the legacy VPN," I point to the open-questions section where VPN complexity was flagged as unknown pending access.
For US clients from Seoul, I schedule discovery in the two-hour overlap window and send a written summary within four hours while it's fresh. The summary is async-friendly and becomes part of the contract record.
How I Build the Hour Estimate
I break work into buckets: provisioning, IAM and networking, observability, CI/CD wiring, documentation, contingency. Each bucket gets a low/high range. I quote the high end of the sum, then add a contingency line item of 15–25% depending on how messy discovery felt.
Buckets I used to forget and no longer do:
- Context switching and communication — 10–15% of total hours for async back-and-forth, especially across time zones.
- Client review latency — if their engineering lead approves PRs once a week, wall-clock stretches even when your hands-on hours don't.
- Rollback and testing — clients imagine migration as a forward-only arrow. I budget explicit hours for rollback drills.
I do not quote flat per-deliverable prices until I've done at least one engagement with that client. Flat fees transfer risk to me. Hourly with a not-to-exceed cap shares risk more fairly on first projects.
Red Flags That Make Me Pad or Walk Away
Some signals predict overrun reliably:
- "We're almost done, we just need someone to finish the Terraform." Almost done projects are rarely almost done.
- Multiple stakeholders on the call with different success criteria. I ask for a single decision-maker named in the SOW.
- Refusal to grant read access before signing. Hidden environments hide hidden hours.
- "Can you start Monday?" without a written scope. Urgency without clarity is expensive.
Walking away is underused. I declined a re-platforming project in Q1 because the CTO wanted a fixed price for "move everything to AWS" with no inventory. That was a scope argument waiting to happen. Two months later a colleague took it and posted privately that the engagement doubled in length.
When Scope Creeps Anyway
Scope creep still happens. The difference with a written SOW is you can name it.
My script is boring and effective: "That's useful work and it's outside the current SOW section 2. I can add it as a change request for approximately X hours — want me to send that today?"
Most reasonable clients say yes. The ones who push back are telling you how the rest of the engagement will go. I complete the in-scope work, hand off cleanly, and don't renew without a different contract structure.
What I'd Tell Past Me
Quote discovery. Write out-of-scope lines even when they feel awkward. Put assumptions in writing. Add contingency without apologizing for it. The 80-hour migration that became 112 taught me that the problem wasn't Kubernetes — it was that I let the client's diagram stand in for discovery.
Good scoping is a form of respect. You're telling the client you take their production environment seriously enough to plan before you touch it.
Renewals: Scoping the Second Engagement
Repeat clients are easier to scope and easier to under-scope. You trust each other, so you skip steps — and then the second project inherits assumptions from the first that no longer hold.
For renewals I still write a SOW, even if it's half a page. I reference the previous engagement explicitly: what we delivered, what we learned about their environment, what's changed since (new services, new compliance requirement, team turnover). I bill discovery again if the gap between contracts is more than six months. Repos drift in six months.
My renewal pricing uses the first project's actual hours as a calibration point, not just the quoted hours. If we quoted 80 and spent 112, the renewal estimate starts from 112-normalized work, not from wishful thinking. I share that calibration with the client — "last time IAM integration took longer than we modeled because of your legacy SSO vendor" — so the new number feels earned, not padded.
Hourly Rate vs. Fixed Bid: How I Choose
Hourly is my default for first engagements with new clients. It aligns incentives: they can narrow scope when they see cost, I can flag risk without absorbing it.
Fixed bids I use when:
- The client has a hard budget cap and accepts a reduced scope document.
- The work is a package I've done repeatedly (baseline EKS landing zone with known modules).
- They want predictability more than flexibility, and the SOW is tight enough that I'm confident.
My fixed bid formula: high estimate × 1.2, rounded up, with out-of-scope list longer than the in-scope list. If that number loses the bid, I lose the bid. Winning a fixed bid you can't deliver is worse than losing on price.
A Minimal SOW Skeleton You Can Copy
This is the structure I paste into a doc and fill in — not legal advice, just engineering scope clarity:
1. Parties & term
2. Objective (1 paragraph)
3. Deliverables (numbered)
4. Out of scope (numbered)
5. Assumptions (numbered)
6. Client responsibilities (access, reviewers, timelines)
7. Change request process
8. Acceptance criteria
9. Hour estimate appendix (buckets + contingency)
10. Payment terms (net-15, milestone, etc.)
Legal terms often live in a master services agreement. The SOW references the MSA and stays technical. Mixing legal and technical in one doc slows signing.
FAQ
Should I quote hours or dollars first?
Hours first, with your rate visible if they ask. Dollars without scope detail invites negotiation on the number alone.
What if they want a ballpark before discovery?
Give a range with assumptions stated aloud: "If staging matches prod and IAM is centralized, 60–90 hours. If not, discovery first."
How do I handle "just a quick fix"?
Quick fixes get a minimum block — two hours billable — or they wait until the next scheduled block on a retainer. Unscoped quick fixes become unpaid architecture consulting.
Retainers vs. One-Off Projects
After a successful project, clients often ask for "a few hours a month" of ongoing help. I scope retainers differently from projects:
- Defined capacity — e.g., 10 hours/month, non-rollover, booked via shared calendar.
- Response time — async within one business day, not 24/7 pager unless priced separately.
- Included work types — office hours, small Terraform changes, review PRs. Excluded: new service migrations, on-call for prod incidents.
Retainers without a written scope become infinite Slack access. I learned that when a client messaged me every evening US time expecting immediate fixes because "we have a retainer." The revised SOW listed channels, hours, and what constitutes an emergency.
AWS-Specific Discovery Questions
Cloud infrastructure scoping differs from general software scoping because the unknown variables in an AWS environment are numerous, specific, and expensive when they surprise you mid-engagement. Generic discovery questions ("what's your tech stack?") don't surface the risks that actually cause overruns.
Questions I ask in every AWS discovery call, regardless of project type:
On IAM and access:
- Who currently has admin access, and is there a break-glass account that isn't one person's personal credentials?
- How is access provisioned for contractors — federated SSO, IAM users, or assumed roles? If IAM users, are there active access keys in any CI/CD systems?
- Are there cross-account trusts I need to be aware of?
On Terraform and IaC state:
- Is there infrastructure that exists outside Terraform? (The honest answer here is almost always yes.)
- Where is Terraform state stored, and is there a state locking mechanism?
- Are there modules imported from third parties that haven't been updated in more than a year?
On networking:
- Are there overlapping CIDR ranges that would block a peering connection I might need?
- Is there a legacy VPN that applications depend on and that isn't documented anywhere?
- What's the NAT Gateway topology — how many, in which AZs, and does all egress traffic run through them?
On operational history:
- What was the last production incident, and what caused it?
- Have there been any billing surprises in the last six months, and were they resolved?
- Are there services that have never had a disaster recovery test?
These questions sound intrusive. They're not — they're professional. An engineer who doesn't ask them is either naive or billing time to discover the answers anyway. Clients who've worked with contractors before generally respect the thoroughness. Clients who've only worked with employees sometimes push back, which is itself useful data about how the engagement will go.
Navigating Enterprise Procurement
Independent contractors selling to enterprise clients encounter procurement processes that weren't designed with individuals in mind — vendor registration, insurance requirements, MSA reviews, and payment terms that assume invoicing to a company, not a person.
What I've learned to ask upfront for enterprise engagements:
Do they require a business entity? Many enterprises won't contract with an individual; they require a business registration. If you're operating as a sole proprietor in Korea, you need to know whether this is a blocker before you invest time in the technical scoping process.
What's the MSA review timeline? Enterprise legal teams reviewing a master services agreement from a new vendor can take two to eight weeks. I ask at the first business conversation, not after the technical proposal. If the client's procurement cycle is twelve weeks and they need the work in six, that's their problem to solve, not mine to absorb by starting work at-risk.
What are the insurance requirements? Some enterprises require professional liability (E&O) insurance with a minimum coverage amount as a condition of the vendor agreement. Korea-based contractors can obtain international professional liability coverage, but it takes time and costs money that should be in the quote.
What are the payment terms? Net-60 or Net-90 payment terms on invoices are standard in some enterprise procurement environments. For a contractor without a large cash reserve, Net-60 on a three-month engagement can be a real cash flow problem. I ask for milestone-based billing (25% on SOW sign, 25% at midpoint review, 50% on acceptance) rather than monthly invoicing when enterprise clients have long payment cycles.
The most common mistake I made early in enterprise engagements was treating procurement as a formality to get through quickly so I could do the technical work. Procurement surprises — unacceptable MSA terms, insurance gaps, entity structure requirements — are contract-blocking, not annoying delays. They warrant the same attention as technical scoping.
When to Walk Away vs. When to Re-Scope
Not every scope problem is a negotiation to have. Some are signals that the engagement won't be productive regardless of how the contract terms are written.
Situations where I re-scope rather than walk away:
Discovery reveals more complexity than the initial conversation suggested. This is normal and expected. I send a revised estimate with an explanation: "Discovery found three additional Terraform state conflicts and a legacy VPN dependency. The revised estimate is X hours to account for migration risk and rollback time." Most clients accept this if the explanation is clear and documented.
The client's definition of "done" shifts. Sometimes the objective changes after work begins — a compliance requirement materializes, a new stakeholder has different success criteria. I treat this as a change request, not an annoyance. Written change request, revised estimate, client approval. The SOW change process exists for exactly this.
Timeline pressure creates quality risk. If a client pushes for a compressed delivery that would require skipping validation steps, I document the risk explicitly: "A two-week delivery is achievable if we skip canary testing and direct-to-production rollback. I recommend against this; if we proceed, the risk of a production incident within 30 days is materially higher." Some clients accept the risk after reading it in writing. That's their decision to make, documented.
Situations where walking away is the right call:
No single decision-maker. Infrastructure decisions that require sign-off from three people who disagree will not get made in time, and you'll deliver to a committee none of whose members will own the outcome. If I can't get one named technical decision-maker in the SOW within the first two conversations, I decline.
Scope is deliberately vague and client resists definition. Some clients want vague scope because it preserves their flexibility to direct your work indefinitely. "You'll know it when you see it" is not an engineering specification. If three attempts at a clear deliverable list result in the client restoring ambiguity each time, the engagement will run over and end badly.
The pattern of the conversation is adversarial. Clients who argue over every clause, demand guarantees you can't give, or assume bad faith before work begins are telling you how the engagement will feel. Contract disputes are expensive and stressful; avoiding them by not starting a bad engagement is cheaper than any billing rate.
Walking away is less common than I expected early in my contracting career. Most scope problems are communication failures, not character failures. But the handful of engagements I should have declined — didn't, because I needed the work or was optimistic — cost me more in time, stress, and reputation risk than the revenue was worth.
Sources
Related Articles
Kubernetes Cost Optimization: What I Actually Do on Production Clusters
11 min read
CareerForeign Income and Korean Tax: What Independent Contractors Working With US and EU Clients Need to Know
12 min read
CareerInfrastructure Documentation That Actually Gets Read: A Contractor's Approach
12 min read
Cloud Engineer · Part-time CS Lecturer · Seoul, South Korea · 5+ years infrastructure
I write about technical career management, variable income, and the performance habits that matter when you work independently — drawing on production infrastructure work and on teaching CS to students who won't accept hand-waving. Read full bio →
This article is for informational purposes only and does not constitute medical, legal, or financial advice.
Browse more articles