Nov 27, 2024·8 min read

Software gross margin: where technical choices cut profit

Software gross margin slips when teams add custom work, overbuild delivery, and ignore cloud waste. This plan shows where profit leaks start.

Software gross margin: where technical choices cut profit

Why profit leaks stay hidden

Gross margin is the money left after you pay the direct cost of delivering your software. If a customer pays $10,000 and you spend $3,000 on hosting, support time, onboarding, and third-party tools to serve that customer, your gross margin is $7,000. That number matters more than total revenue if you want a software business that keeps earning.

The problem is simple. Sales are easy to see, but delivery cost usually is not. New contracts show up in the bank account, the CRM, and the sales report. Extra engineering hours, rising cloud bills, and manual support work sit in different systems, so the damage looks smaller than it is.

Strong sales can hide weak delivery economics for months. A team may feel good because customer count keeps rising, even while each new account adds a little more custom code, a few more support hours, and another service to run. Revenue goes up. Margin slides down.

Founders often miss this because revenue loss is loud. A churned customer or a bad sales month gets attention fast. Margin loss is quieter. It shows up as overtime, one more premium cloud service, one more product exception, or one more customer promise nobody priced correctly.

Another common mistake is mixing initial setup cost with repeat delivery cost.

An initial setup cost might be a migration, data import, or special onboarding project. It can hurt one deal and then disappear. Repeat delivery cost is worse. That is the custom dashboard your team has to keep updating, the extra API calls you pay for every month, or the support workflow that always needs a human. Once that cost sticks to the account, it follows the revenue every month.

That is why healthy revenue creates false comfort. If nobody separates temporary work from permanent cost, the business can look fine on the surface while profit leaks through a hundred small delivery decisions. By the time the team asks why margins feel tight, those habits already feel normal.

When delivery work stops paying for itself

Gross margin falls when a team spends more time delivering promises than building product value that repeats across the customer base.

Product work usually pays back many times. One fix or feature can help every customer, cut support tickets, or make sales easier. Custom work usually pays once. A special export, extra field, or odd workflow may win a deal, but the team owns it long after the invoice is paid. Support work protects revenue, but it rarely compounds. If the same setup help, data repair, or bug triage shows up every week, margin shrinks.

The hidden cost is rarely the code alone. A "small" request often brings two extra meetings, manual QA, an unusual deployment step, and a handoff between product, engineering, and support. Each piece looks minor on its own. Together they turn a healthy feature into service work with thin returns.

Small exceptions also spread faster than most teams expect. One customer gets a custom permission rule. The next customer wants the same rule with a twist. Soon the roadmap carries branching logic, longer test cycles, special support notes, and more room for mistakes. The team still says it is building the product, but part of the codebase now exists for a handful of accounts.

That is when service work starts to look like product revenue. The contract still sits in recurring revenue on a dashboard, yet the delivery model looks more like custom software work: bespoke requests, manual care, and constant interpretation. The company says "SaaS." The cost structure says "agency."

This usually does not happen because the team is careless. It happens because nobody stops to ask a basic question: will this request make the product better for many customers, or will it create permanent cost for one account? If the answer is the second one, the work needs a different price, a clear limit, or a polite no.

When custom requests become permanent cost

One client asks for a small exception, and the team says yes because the deal looks worth it. A second client wants something close, but not quite the same. Six months later, the product has extra branches, special settings, odd edge cases, and support notes that only two engineers understand.

That is how margin slips. The first request feels cheap. The long tail does not.

Custom work often stays in the code long after the contract ends. Engineers keep testing it during every release. Product managers keep it in mind when they plan changes. Support teams answer questions about it. New hires spend time learning it. If the original client leaves, the cost stays.

The pricing trap usually starts before the code. Teams give away small changes to keep momentum. Sales promises a quick turnaround before anyone scopes the work. The statement of work stays vague, so every follow-up becomes a debate. Urgent requests make this worse because rushed work creates messy code, thin testing, and cleanup nobody budgets for.

A custom feature also changes maintenance after the deal closes. Someone has to watch logs, fix bugs, update docs, and check that the feature still works after framework upgrades or billing changes. One exception in permissions or reporting can add hours to every release. You may never see that cost on the invoice, but payroll sees it.

A few rules help. Charge for any request that adds new logic, not just a new screen. Put an end date on custom work unless it becomes part of the main product. Refuse vague scope. If sales wants a fast answer, give a priced estimate with clear limits. If custom code stays live after launch, add a maintenance fee. And before approving anything, ask one hard question: will three more clients ask for this next quarter?

A good technical leader protects margin by treating exceptions as product decisions, not favors. That sounds strict, but it saves teams from carrying permanent cost they never meant to accept.

Infrastructure habits that drain profit

A lot of margin loss looks harmless when you see one bill at a time. One larger server, one staging environment nobody shut down, one extra tool for logs or testing. Each choice feels small. Together they squeeze margin without any single dramatic mistake.

Hidden waste

The usual trouble spots are boring, which is exactly why teams miss them. Servers stay sized for a traffic spike that passed months ago. Dev and staging environments run all night and all weekend. Two or three tools do the same job for alerts, logs, tickets, or test runs. Old storage volumes, snapshots, and databases sit around because nobody owns them. Temporary cloud features stay on long after the original need disappears.

None of this gets much attention in a product meeting. It shows up later as a cloud bill that rises faster than revenue. If the team also takes custom software work, the problem grows. Extra environments, custom integrations, and customer-specific jobs often stay alive long after the work stopped making money.

Weak monitoring makes this worse. If nobody tracks cost by service, job duration, error rates, and usage trends, the team cannot see what actually costs money. People start guessing. They add more capacity to feel safe, or they buy another tool because the first one feels noisy. Caution is fine. Blind caution is expensive.

Convenience gets expensive

Manual deploys follow the same pattern. Pushing changes by hand feels cheaper than setting up deployment automation. For a month or two, that may even be true. Then one release fails, two engineers spend half a day rolling it back, and support gets dragged in because customers saw errors.

Flaky tests create the same kind of leak. Engineers rerun pipelines, skip checks, or patch production issues after release. That rework does not land on a cloud invoice, but it still hits profit. The team ships less, spends more time fixing avoidable problems, and grows nervous about every change.

Short-term convenience wins because the cost arrives later. Cleaning up idle environments, shrinking oversized servers, removing duplicate tools, and automating deploys takes work now. Skipping that work creates a monthly tax on the business. Good technical leadership reviews infrastructure the same way it reviews product spend: keep what gets used, cut what does not, and stop paying for comfort that no longer earns its keep.

How to review margin risk step by step

Work With a Fractional CTO
Get a clear view of cost, custom work, and delivery risk before margins slip further.

Most margin problems do not start in finance. They start in the daily work between a signed deal and the next support ticket. If you want to protect software gross margin, review the whole path a customer creates inside your team.

Start with one customer type, not the whole business. Pick a recent deal, then trace every delivery step from handoff to onboarding to bug fixes to account support. Include the work people forget, like internal meetings, manual setup, special reports, and late night cloud cleanup after a release.

  1. Write down each activity in order. Keep it simple: who does it, how often it happens, and how long it usually takes.
  2. Add rough cost, not perfect cost. Use team hourly cost, monthly tool cost, and cloud usage tied to that customer or feature.
  3. Mark anything that repeats for every customer. Repeated work is where margin slips fastest because growth multiplies it.
  4. Decide what each expensive step needs: cut it, automate it, standardize it, or reprice it.
  5. Check the same flow again after one month and compare the numbers.

Rough numbers are enough to start. If onboarding takes a developer three hours, support spends ninety minutes a month on the same customer issue, and a custom data export adds extra compute every week, you already have a useful picture. Waiting for perfect data usually means nobody changes anything.

Watch for custom work that pretends to be small. A sales promise like "just one custom integration" often adds testing time, support load, and upgrade pain for months. The first invoice may cover the build. It rarely covers the long tail.

A simple rule helps: if a step happens more than twice a month, treat it as a system problem, not a team habit. Good reviews get specific fast. You should end with a short action list, an owner for each item, and a date to measure again. If the second review shows the same manual cost, the process is the problem, not the spreadsheet.

A simple example from a growing SaaS team

A small B2B SaaS team had about 120 customers and a staff of eight. Most customers used the same product, the same shared setup, and the same onboarding flow. Revenue was not huge yet, but gross margin stayed healthy because the team built once and supported many.

Then larger customers started to arrive. That looked like a win. Three new accounts each paid about four times more than a normal customer, so sales pushed hard to close them.

The trouble started with promises made during the deal. One customer wanted custom reports for its finance team. Another asked for private hosting because its IT lead felt safer that way. A third wanted a special export format and a few approval rules that nobody else used.

Revenue went up fast. Margin did not.

The custom reports took one engineer a few hours every week because each new data field changed the logic. The private hosting setup needed its own monitoring, backups, deployment steps, and support checks. The export format looked small at first, but every product update now needed extra testing because that one customer could break in a different way.

Within two quarters, gross margin dropped from 78% to 61%. Cloud spend rose, but labor did more damage. The team spent more time on work that only one account used, and that time did not help the rest of the customer base.

They fixed it with a few clear rules. Custom reporting became a standard paid package with firm limits. New enterprise customers moved onto shared infrastructure unless a contract clearly covered the full cost of private hosting. The team also added change fees for special requests and monthly support fees for anything that created ongoing work.

One customer stayed on a private setup, but now paid enough to cover it. Another accepted the standard reporting package after seeing the price of custom work. The third got a cleaner export that fit the product instead of a separate branch of code.

Three months later, margin climbed back to 72%. Support tickets dropped. Releases got simpler. The team still had to watch discounting and slow support growth, because both can hide the same problem in a quieter form. But the main leak was gone: they stopped selling exceptions as if they were normal product revenue.

Mistakes teams make when they cut costs

Price Custom Work Better
Set limits, maintenance fees, and scope before one request becomes ongoing cost.

The first mistake is easy to spot once you know where to look. Teams cut the bill they can see and ignore the time they cannot. A company cancels a cheap tool, then asks engineers to do the same work by hand. The monthly invoice drops, but payroll stays the same and delivery gets slower. That hurts margin more than the tool ever did.

This shows up in small ways. A team removes a paid deployment helper, a test dashboard, or an internal admin tool because it looks optional. Then senior engineers spend three or four hours a week covering the gap. If two people do that every week, the "savings" disappear fast.

Another common mistake is cutting quality checks. Teams remove tests, skip code review, or relax release checks because they want fewer delays. For a week or two, this can look cheaper. Then bugs reach customers, the team stops feature work to fix them, and one incident wipes out months of savings.

Cheap delivery is not the same as cheaper delivery. If engineers spend Friday night rolling back a bad release, the company still pays for that work. It just pays in a messier way.

A hiring freeze can create the same trap. Sometimes it is reasonable, but it only works if the delivery model changes too. If the business keeps accepting heavy custom software work, keeps every customer promise, and keeps the same deadlines, the existing team absorbs the load. Work slows down, support grows, and burnout becomes a hidden cost.

Teams also chase lower cloud bills without measuring what customers feel. They cut logging, shrink servers too far, or delay database work just to make the hosting number look better. If pages load slower, jobs fail more often, or the app goes down at busy times, the cheaper infrastructure costs more than it saves.

A better test is simple:

  • Does this remove work, or just move it to engineers?
  • Will this increase the chance of bugs or outages?
  • Are we fixing the delivery model, or only freezing headcount?
  • Will customers notice slower speed or worse reliability?

Good technical leaders usually start there. The safest cuts reduce rework, cut back custom promises, and remove waste before it reaches customers.

A quick margin check this month

Fix Manual Delivery Steps
Find the setup, QA, and release work your team still does by hand.

A monthly margin check should take 20 minutes. If it needs a slide deck, you are already doing too much. The goal is to find the work and spend that grew quietly while revenue stayed flat.

Ask the team five direct questions. If nobody can answer one in under two minutes, that gap is part of the problem.

  • Can anyone name the three biggest delivery costs right now? For most software teams, that means engineering time, support time, cloud bills, contractor spend, or customer success work. If people guess instead of knowing, margin is moving without control.
  • Is any customer getting custom work without a price, a time limit, or written approval? Small favors often turn into permanent obligations.
  • Did cloud spend rise faster than active usage? A bigger bill is not always bad. A bigger bill with flat users, flat traffic, or flat revenue usually means waste or oversized infrastructure.
  • Do engineers still repeat manual setup, QA, or support tasks every week? If the same person spends every Friday doing releases by hand, fixing test data, or answering the same issue, that time comes straight out of margin.
  • Did one urgent client request change the core product? This is where teams make expensive promises. A rushed change for one account can add testing, support, edge cases, and product confusion for everyone else.

You do not need perfect numbers to act. You need one owner for each issue, one rough monthly cost, and one deadline to fix it, price it, or stop doing it.

If a cost repeats, treat it as a product decision, not a small annoyance. If two or more answers look messy this month, put them on the operating list and attach a dollar estimate to each before the month ends.

What to do next

If your software gross margin feels tighter than it should, do not start with a whole company cost-cutting plan. Pick one leak, give one person ownership, and set one deadline for action this week.

That leak might be a custom client request nobody priced properly, a cloud bill that keeps growing faster than revenue, or a support burden caused by rushed delivery. A named owner matters because profit problems often sit in the space between product, engineering, and finance.

A simple monthly review is usually enough to stop small leaks from turning into permanent cost. Look at the same few areas each month: scope added outside the original plan, infrastructure cost by product area or customer segment, support load caused by bugs or special features, and team time spent on work that does not improve the core product.

You do not need a perfect dashboard to start. A shared document and 30 minutes on the calendar can surface a lot. After two or three months, patterns get hard to ignore.

If the team cannot explain where delivery cost really comes from, an outside technical review can help. Oleg Sotnikov at oleg.is works as a fractional CTO and startup advisor, and this kind of review fits that role well: look at custom work, infrastructure, and team habits, then decide what to cut, automate, reprice, or retire.

A good review should end with a short list of changes, owners, and dates. If one custom feature needs retirement, retire it. If one service should move to a simpler setup, plan it. If one part of the product creates constant support work, fix that before building something new.

Profit rarely comes back through one big move. It usually returns through a few clear decisions that a team finally makes and follows through on.

Frequently Asked Questions

What is software gross margin?

Gross margin is the money left after you pay to deliver your software. Count hosting, support time, onboarding work, third-party tools, and any customer-specific labor. If that leftover amount keeps shrinking, revenue alone will not save the business.

Why can revenue go up while profit goes down?

Because delivery cost can grow in the background while sales look strong. New deals look obvious on reports, but extra support hours, cloud spend, custom code, and manual work often hide across different systems.

How do I separate setup cost from ongoing cost?

Treat one-time setup as work that ends after launch, like a migration or initial data import. Treat repeat delivery cost as anything that follows the account every month, like manual support, extra API usage, custom reports, or special hosting.

When should we refuse a custom request?

Say no when the request helps one account but adds permanent work for the team. If you still want the deal, give the request a price, a clear limit, and a maintenance plan instead of treating it like a small favor.

How should we price custom work?

Charge for any request that adds new logic, ongoing support, or extra testing. Put the scope in writing, add a time limit if the work will not join the main product, and include a monthly fee if the team must keep it running.

Which infrastructure habits usually hurt margin first?

Oversized servers, idle staging environments, duplicate tools, and manual deploys usually show up first. Flaky tests also hurt margin because engineers spend time rerunning jobs, fixing avoidable issues, and handling risky releases.

How often should we review margin risk?

Run a short review every month. Pick one customer type or one recent deal, trace the delivery steps, attach rough cost to each step, and look for work that repeats often.

What is a quick way to find hidden delivery work?

Start with one recent customer and map everything the team did after the deal closed. Include meetings, setup, support, bug fixes, special reports, and cloud usage. Rough numbers work fine if they help you spot repeat work and stop it.

What cost cuts usually backfire?

Teams get into trouble when they remove a visible tool cost and push the work onto engineers instead. They also create problems when they cut testing, code review, or reliability work just to make a monthly bill look smaller.

When does it make sense to bring in a fractional CTO?

Bring one in when the team cannot explain where delivery cost comes from or when custom work, infrastructure spend, and support load keep growing together. A fractional CTO can review the flow, price the exceptions properly, and help you cut or automate the work that keeps eating margin.