Replacing getAddress.io? Free drop-in replacement →
Development 10 min read

How to Calculate Property Development Feasibility in the UK

Before you make an offer on a site or appraise a scheme, you need to know the numbers. This guide walks through GDV, development costs, profit on cost, and residual land value — plus how to pull real sold price comparables from the API to underpin your end values.

By Homedata ·

Development feasibility is the process of working out whether a site can generate a return that justifies the risk. The maths is straightforward. The hard part is getting the inputs right — especially the end values, which are where most feasibilities go wrong.

The development feasibility formula

Every development appraisal starts with the same three numbers:

1

Gross Development Value (GDV)

Total revenue if every unit sells at the projected price. GDV = number of units × average end value per unit.

2

Total development cost (TDC)

Land + build cost + professional fees + finance costs + contingency + planning obligations.

3

Development profit

GDV minus TDC. Expressed as a percentage of GDV (profit on GDV) or a percentage of cost (profit on cost).

Key metrics

Profit on GDV (%) = (GDV − TDC) ÷ GDV × 100

Profit on cost (%) = (GDV − TDC) ÷ TDC × 100

Residual land value = GDV − (build + fees + finance + target profit)

The RICS benchmark for a viable residential scheme is 20% profit on GDV (roughly equivalent to 25% on cost). Below 15% and most developers and funders won't proceed — the risk-to-return ratio doesn't justify it.

Want to run the numbers? Use our free GDV calculator — it covers all the inputs below and gives you profit on GDV, profit on cost, and return on equity in one screen.

Breaking down development costs

A reliable appraisal accounts for all six cost buckets:

Cost item Typical range Notes
Land cost Varies Purchase price + stamp duty + acquisition costs (~2-3%)
Build cost £1,800–£3,500/m² BCIS data for your region and scheme type. Flats typically £2,500+
Professional fees 8–12% of build cost Architect, QS, planning consultant, structural engineer
Finance costs 6–9% p.a. Development finance on land + build. Typically 65–75% LTC
Contingency 5–10% of build cost Higher for older buildings or unknown ground conditions
Planning obligations Varies S106 contributions, CIL, affordable housing (up to 35% of units in some LAs)

Getting end values right

Your GDV is only as good as your end values. Use the wrong comparable sales and a scheme that looks viable falls apart at tender, or worse — post-completion.

The Homedata comparables API returns the 20 most recent sold prices within 0.5 miles of any UPRN, filtered by bedrooms and property type. That means you can estimate end values for each unit type in a scheme using actual, recent evidence — not an agent's optimistic projection.

Estimate GDV from comparable sales
import requests

API_KEY = "YOUR_API_KEY"
HEADERS = {"Authorization": f"Api-Key {API_KEY}"}
BASE_URL = "https://api.homedata.co.uk"

# Site UPRN — any property on or adjacent to your site works as the reference
SITE_UPRN = 100023336956

# ── Step 1: Pull 3-bed terraced sale comparables ─────────────────────────
params = {
    "bedrooms": 3,
    "property_type": "Terraced",
    "event_type": "sold",
    "count": 20
}
resp = requests.get(f"{BASE_URL}/api/comparables/{SITE_UPRN}/", headers=HEADERS, params=params)
data = resp.json()

# ── Step 2: Extract sold prices ──────────────────────────────────────────
sold_prices = [
    c["sold_let_price"]
    for c in data["comparables"]
    if c["sold_let_price"] and c["transaction_type"] == "Sale"
]

# ── Step 3: Average end value per unit ───────────────────────────────────
avg_end_value = sum(sold_prices) / len(sold_prices) if sold_prices else 0
print(f"Comparables found:   {len(sold_prices)}")
print(f"Average end value:   £{avg_end_value:,.0f}")

# ── Step 4: GDV for a 10-unit terraced scheme ────────────────────────────
NUM_UNITS = 10
gdv = NUM_UNITS * avg_end_value
print(f"\nGDV ({NUM_UNITS} units):         £{gdv:,.0f}")

# ── Step 5: Quick feasibility ────────────────────────────────────────────
land_cost     = 850_000
build_cost    = 2_100 * 85 * NUM_UNITS  # £2,100/m² × 85m² average
fees          = build_cost * 0.10       # 10% professional fees
finance       = (land_cost + build_cost) * 0.08  # 8% on land + build
contingency   = build_cost * 0.07       # 7% contingency
s106          = 5_000 * NUM_UNITS       # £5k/unit S106

total_cost    = land_cost + build_cost + fees + finance + contingency + s106
profit        = gdv - total_cost
profit_on_gdv = (profit / gdv * 100) if gdv else 0

print(f"\n── Feasibility summary ──────────")
print(f"GDV:                 £{gdv:,.0f}")
print(f"Total cost:          £{total_cost:,.0f}")
print(f"Profit:              £{profit:,.0f}")
print(f"Profit on GDV:       {profit_on_gdv:.1f}%")
print(f"Viable:              {'✓ Yes' if profit_on_gdv >= 20 else '✗ Below 20% threshold'}")

Example output

Comparables found:   18
Average end value:   £387,500

GDV (10 units):      £3,875,000

── Feasibility summary ──────────
GDV:                 £3,875,000
Total cost:          £2,909,500
Profit:              £965,500
Profit on GDV:       24.9%
Viable:              ✓ Yes

Auth: all code examples use Api-Key YOUR_API_KEY. The comparables endpoint requires a key — register for a free tier to get one.

Residual land value: working backwards

When you're appraising a site before you know the asking price, flip the calculation. Residual land value (RLV) is the maximum you can pay for a site and still hit your profit target.

Residual land value formula

RLV = GDV − (build + fees + finance + contingency + S106) − target profit

If the asking price is higher than your RLV, the scheme doesn't work at that price — no amount of value engineering will fix it. Knowing your RLV before you enter a bidding situation is the single most important number in any development appraisal.

Calculate residual land value
TARGET_PROFIT_ON_GDV = 0.20  # 20% — minimum viable return

# Using avg_end_value and NUM_UNITS from the previous example
gdv           = avg_end_value * NUM_UNITS
target_profit = gdv * TARGET_PROFIT_ON_GDV

# Build-side costs without land
build_cost    = 2_100 * 85 * NUM_UNITS
fees          = build_cost * 0.10
contingency   = build_cost * 0.07
s106          = 5_000 * NUM_UNITS

# Finance on build only (land not yet known)
finance_build = build_cost * 0.06

non_land_costs = build_cost + fees + finance_build + contingency + s106

# Residual: what's left after costs and target profit
rlv = gdv - non_land_costs - target_profit
print(f"GDV:                 £{gdv:,.0f}")
print(f"Non-land costs:      £{non_land_costs:,.0f}")
print(f"Target profit (20%): £{target_profit:,.0f}")
print(f"Max land bid (RLV):  £{rlv:,.0f}")

Sensitivity: the number everyone skips

A 5% drop in end values across a 10-unit scheme can wipe £190k off your GDV. A 10% cost overrun adds another £180k to the other side. The gap between viable and unviable is rarely large.

Before you commit, stress-test your feasibility against three scenarios:

Base case

Comparable evidence at face value. Your target margin.

Downside: −5% GDV

Market softens before completion. Still viable? Still bankable?

Stress: −10% GDV, +10% cost

If the scheme only works in perfect conditions, it doesn't work.

Building this into a proptech platform

If you're building a valuation tool, land-sourcing platform, or development appraisal product, the comparables API gives you the market evidence layer. Combine it with price trends for outcode-level market direction:

Combine comparables + price trend for market-adjusted GDV
import requests, statistics

API_KEY = "YOUR_API_KEY"
HEADERS = {"Authorization": f"Api-Key {API_KEY}"}
BASE_URL = "https://api.homedata.co.uk"

SITE_UPRN = 100023336956
OUTCODE   = "SE22"          # Match your site's outcode

# ── Comparables: recent sold prices ──────────────────────────────────────
comps = requests.get(
    f"{BASE_URL}/api/comparables/{SITE_UPRN}/",
    headers=HEADERS,
    params={"bedrooms": 3, "property_type": "Terraced", "event_type": "sold", "count": 20}
).json()

sold_prices = [
    c["sold_let_price"]
    for c in comps["comparables"]
    if c["sold_let_price"] and c["transaction_type"] == "Sale"
]
avg_comparable = statistics.median(sold_prices) if sold_prices else 0

# ── Price trend: 12-month direction ──────────────────────────────────────
trend = requests.get(
    f"{BASE_URL}/api/price_trends/{OUTCODE}/",
    headers=HEADERS
).json()

# monthly_average_prices is a dict of "YYYY-MM" → median price
monthly = trend.get("monthly_average_prices", {})
if len(monthly) >= 12:
    sorted_months = sorted(monthly.keys())
    price_12m_ago = monthly[sorted_months[-12]]
    price_now     = monthly[sorted_months[-1]]
    trend_pct     = (price_now - price_12m_ago) / price_12m_ago * 100
else:
    trend_pct = 0

print(f"Median comparable:    £{avg_comparable:,.0f}")
print(f"12-month price trend: {trend_pct:+.1f}% in {OUTCODE}")

# Apply a conservative 50% weight to the trend direction
adjusted_value = avg_comparable * (1 + (trend_pct / 100) * 0.5)
print(f"Market-adjusted end:  £{adjusted_value:,.0f}")

API endpoints used in this post

Endpoint What it returns Auth
/api/comparables/{uprn}/ Up to 200 recent sold/let prices within 0.5 miles. Filtered by bedrooms + property type. API key
/api/price_trends/{outcode}/ 30 years of median prices by month. Returns monthly_average_prices dict + volatility score. API key

Try the GDV calculator

Enter your units, land cost, and build cost. Get GDV, profit on GDV, profit on cost, and residual land value in one screen — no signup needed.

Related guides