Finance & banking · The method — the desk, the system, and the two models

A DCF you can defend

Everyone can recite the five steps. This lesson builds the model and then interrogates it, which produces the three facts that make the recitation defensible — how much of the answer is one division, how wide the range gets when two inputs move by amounts nobody would argue with, and the cross-check that catches a growth rate implying an absurd exit multiple.

22 min read Free to read Patterns: discounted-cash-flow

What you'll be able to do

Before this: the-three-statements-as-one-system

"Walk me through a DCF" has a canonical five-step answer, and every candidate has it:

  1. Project free cash flow, typically five to ten years.
  2. Discount at the weighted average cost of capital.
  3. Compute a terminal value for everything after the forecast.
  4. Discount that back too, and sum to get enterprise value.
  5. Subtract net debt and divide by fully diluted shares to get an implied share price.

That answer is correct and it is not worth much, because everyone gives it. What distinguishes a good answer is what you say next: which step carries the weight, how wrong the output can be, and what you would do to check yourself. Those three things are properties of the model, so the way to know them is to run one.

The pieces, and what each one is a required return on

Unlevered free cash flow (FCFF). Start from EBIT, tax it, add back depreciation and amortisation, subtract capital expenditure and the increase in net working capital. Interest appears nowhere, deliberately — this is cash available to all capital providers, before deciding who gets what, which is why it gets discounted at a blended rate.

This is the cash flow statement rearranged, which is why the previous lesson comes first. If you can derive the cash flow statement from the income statement, free cash flow is not a formula to remember.

WACC. Two legs, and both are required returns rather than costs you write cheques for:

  • Cost of equity, from CAPM: the risk-free rate plus beta times the equity risk premium. The risk-free rate should be a government yield of matched duration; beta should be relevered to the target capital structure.
  • After-tax cost of debt: what the company borrows at today, times one minus the tax rate, because interest is deductible. The coupon on debt issued five years ago is not the cost of debt.

The weights are market-value weights at the target structure, not book values off the balance sheet.

Terminal value. Two accepted methods. Growth in perpetuity — the last forecast cash flow grown forever at a rate conventionally held to roughly 1%–3%, proxied off long-run GDP or inflation. Or an exit multiple, usually EV/EBITDA taken from comparable companies. The lesson's cell uses the first and then checks it against the second, which is the move most candidates never make.

WatchFinanceable Training · 13:12

The spoken version of the answer, in the five steps an interviewer is waiting to hear ticked off. Watch 04:18 for terminal value in particular, then come back — the model below exists to show you how much of the whole valuation those two minutes are responsible for.

Jump to the part you need

Running it

Every input below is an illustrative assumption chosen to make the arithmetic legible. None of them is a market quote, and in a real answer each is a number you would have to source and defend out loud.

JavaScript
// A DCF, built from stated assumptions, then interrogated.
//
// The point of running it rather than reciting it: a DCF is not mostly a
// forecast. It is mostly a terminal value, and the terminal value is one
// division by a small number. This cell prints how much of the answer that
// single division is responsible for, and what happens to the answer when the
// two inputs to it move by amounts nobody would argue with.
//
// Every input below is an ILLUSTRATIVE assumption chosen to make the
// arithmetic legible -- not a market quote. In a real answer each one is a
// number you have to source and defend out loud.

const REV0      = 1000;                       // last actual year revenue
const GROWTH    = [0.08, 0.07, 0.06, 0.05, 0.04];  // stage 1, 5 years
const EBITDA_M  = 0.25;                       // EBITDA margin, held flat
const DA_PCT    = 0.06;                       // D&A as % of revenue
const CAPEX_PCT = 0.07;                       // capex as % of revenue
const NWC_PCT   = 0.10;                       // NWC as % of INCREMENTAL revenue
const TAX       = 0.25;

// WACC from its parts. Both legs are required-return numbers, not costs you pay.
const RF   = 0.042;   // risk-free: a government yield of matched duration
const ERP  = 0.050;   // equity risk premium
const BETA = 1.10;    // relevered to the target capital structure
const KD   = 0.055;   // pre-tax cost of debt: what the company borrows at today
const WE   = 0.80, WD = 0.20;   // MARKET-value weights, at target structure

const KE   = RF + BETA * ERP;
const WACC = WE * KE + WD * KD * (1 - TAX);

const NET_DEBT = 300;
const SHARES   = 100;      // diluted, treasury-stock method
const G        = 0.025;    // perpetuity growth: <= long-run nominal GDP

/** Stage 1 unlevered free cash flow. FCFF, so no interest anywhere. */
function forecast() {
  const rows = [];
  let rev = REV0;
  for (let i = 0; i < GROWTH.length; i++) {
    const prev = rev;
    rev = rev * (1 + GROWTH[i]);
    const ebitda = rev * EBITDA_M;
    const da     = rev * DA_PCT;
    const ebit   = ebitda - da;
    const nopat  = ebit * (1 - TAX);
    const capex  = rev * CAPEX_PCT;
    const dNWC   = (rev - prev) * NWC_PCT;
    rows.push({
      year: i + 1, rev, ebitda, da, ebit, nopat, capex, dNWC,
      fcf: nopat + da - capex - dNWC,
    });
  }
  return rows;
}

/** PV of stage 1 + PV of terminal value. `midYear` applies the convention. */
function value(rows, wacc, g, midYear = false) {
  let pv1 = 0;
  for (const r of rows) {
    const t = midYear ? r.year - 0.5 : r.year;
    pv1 += r.fcf / (1 + wacc) ** t;
  }
  const last = rows[rows.length - 1];
  const tv = (last.fcf * (1 + g)) / (wacc - g);
  const pvTv = tv / (1 + wacc) ** rows.length;   // TV sits at the END of year 5
  const ev = pv1 + pvTv;
  return { pv1, tv, pvTv, ev, share: pvTv / ev,
           equity: ev - NET_DEBT, price: (ev - NET_DEBT) / SHARES,
           impliedExit: tv / last.ebitda };
}

const rows = forecast();
const base = value(rows, WACC, G);

console.log("cost of capital");
console.log("  cost of equity  = " + (RF * 100).toFixed(1) + "% + " + BETA.toFixed(2) +
            " x " + (ERP * 100).toFixed(1) + "% = " + (KE * 100).toFixed(2) + "%");
console.log("  after-tax debt  = " + (KD * 100).toFixed(1) + "% x (1 - " + TAX +
            ") = " + (KD * (1 - TAX) * 100).toFixed(2) + "%");
console.log("  WACC            = " + (WE * 100).toFixed(0) + "% x " + (KE * 100).toFixed(2) +
            "% + " + (WD * 100).toFixed(0) + "% x " + (KD * (1 - TAX) * 100).toFixed(2) +
            "% = " + (WACC * 100).toFixed(2) + "%");
console.log("");

console.log("stage 1 free cash flow (FCFF -- no interest, this is pre-financing)");
console.log("  yr   revenue   EBITDA     EBIT    NOPAT    capex    dNWC      FCF   discount       PV");
for (const r of rows) {
  const df = 1 / (1 + WACC) ** r.year;
  console.log(
    "   " + r.year,
    r.rev.toFixed(0).padStart(9), r.ebitda.toFixed(1).padStart(8),
    r.ebit.toFixed(1).padStart(8), r.nopat.toFixed(1).padStart(8),
    r.capex.toFixed(1).padStart(8), r.dNWC.toFixed(1).padStart(7),
    r.fcf.toFixed(1).padStart(8), df.toFixed(4).padStart(10),
    (r.fcf * df).toFixed(1).padStart(9)
  );
}
console.log("");

console.log("bridging to a share price");
console.log("  PV of stage 1 FCF          " + base.pv1.toFixed(1).padStart(9));
console.log("  terminal value at yr 5     " + base.tv.toFixed(1).padStart(9) +
            "   = FCF5 x (1 + g) / (WACC - g)");
console.log("  PV of terminal value       " + base.pvTv.toFixed(1).padStart(9));
console.log("  enterprise value           " + base.ev.toFixed(1).padStart(9));
console.log("  less net debt              " + (-NET_DEBT).toFixed(1).padStart(9));
console.log("  equity value               " + base.equity.toFixed(1).padStart(9));
console.log(("  / " + SHARES + " diluted shares").padEnd(29) + base.price.toFixed(2).padStart(9) + "   per share");
console.log("");
console.log("  terminal value is " + (base.share * 100).toFixed(1) +
            "% of enterprise value.");
console.log("  Five years of forecasting -- margins, capex, working capital, the");
console.log("  whole model -- account for the other " + ((1 - base.share) * 100).toFixed(1) + "%.");
console.log("");

// ── Sensitivity: the two inputs to the division that owns 3/4 of the answer ──
const waccs = [WACC - 0.010, WACC - 0.005, WACC, WACC + 0.005, WACC + 0.010];
const gs    = [0.015, 0.020, 0.025, 0.030, 0.035];
console.log("implied share price:  WACC across, perpetuity growth down");
console.log("         " + waccs.map((w) => ((w * 100).toFixed(2) + "%").padStart(9)).join(""));
for (const g of gs) {
  let line = "  g " + (g * 100).toFixed(1) + "% ";
  for (const w of waccs) line += value(rows, w, g).price.toFixed(2).padStart(9);
  console.log(line);
}
const lo = value(rows, waccs[waccs.length - 1], gs[0]).price;
const hi = value(rows, waccs[0], gs[gs.length - 1]).price;
console.log("");
console.log("  Corner to corner: " + lo.toFixed(2) + " to " + hi.toFixed(2) +
            " -- a " + (hi / lo).toFixed(1) + "x spread, from moving");
console.log("  WACC by 1 point and g by 1 point. Nobody in the room could tell you");
console.log("  which cell is right. This is why the output of a DCF is a RANGE, and");
console.log("  why a candidate who says \"$" + base.price.toFixed(2) +
            "\" with a straight face has misunderstood");
console.log("  the instrument.");
console.log("");

// ── The cross-check almost nobody volunteers ──────────────────────────────
console.log("the cross-check: what exit multiple did your g quietly assume?");
console.log("  g = " + (G * 100).toFixed(1) + "% and WACC = " + (WACC * 100).toFixed(2) +
            "% imply a terminal EV/EBITDA of " + base.impliedExit.toFixed(1) + "x");
console.log("  (TV of " + base.tv.toFixed(0) + " over year-5 EBITDA of " +
            rows[rows.length - 1].ebitda.toFixed(1) + ")");
console.log("");
console.log("  g      implied terminal EV/EBITDA");
for (const g of gs) {
  const v = value(rows, WACC, g);
  console.log("  " + (g * 100).toFixed(1) + "%   " + v.impliedExit.toFixed(1).padStart(5) + "x");
}
console.log("");
console.log("  Run it the other way to sanity-check yourself: if comparable mature");
console.log("  companies trade at 9x EBITDA, then g must satisfy");
console.log("  FCF5 x (1+g)/(WACC-g) = 9 x EBITDA5.");
// Invert for g given a target exit multiple: solve TV = m * EBITDA5.
function gForMultiple(m) {
  const last = rows[rows.length - 1];
  const target = m * last.ebitda;
  // FCF5(1+g)/(WACC-g) = target  ->  g (FCF5 + target) = target*WACC - FCF5
  return (target * WACC - last.fcf) / (last.fcf + target);
}
for (const m of [8, 9, 10, 12]) {
  const g = gForMultiple(m);
  const v = value(rows, WACC, g);
  console.log("    " + (m + "x").padStart(3) + "  ->  g = " + (g * 100).toFixed(2) + "%" +
              "   (check: implied multiple " + v.impliedExit.toFixed(1) + "x)" +
              (g > 0.03 ? "   <- outside the 1-3% convention" : ""));
}
console.log("");

// ── Mid-year convention ───────────────────────────────────────────────────
const mid = value(rows, WACC, G, true);
console.log("mid-year convention: cash arrives through the year, not on 31 Dec.");
console.log("  end-of-year stage 1:  price " + base.price.toFixed(2));
console.log("  mid-year stage 1:     price " + mid.price.toFixed(2) +
            "   (+" + ((mid.price / base.price - 1) * 100).toFixed(1) + "%)");
console.log("  Worth about " + ((mid.price / base.price - 1) * 100).toFixed(1) +
            "% here, i.e. less than one column of the grid above.");
console.log("  Mention it to show you know it exists; do not spend your airtime on");
console.log("  a refinement an order of magnitude smaller than your error bars.");
From discounted cash flow to equity value
+601.4M +1,920.3M -300M 2,221.7M
PV of stage-1 FCFPV of terminal valueLess net debtEquity value
addssubtractsresult

Three bars and one of them is most of the chart. The terminal value contributes $1,920.3M of a $2,521.7M enterprise value — 76.2% — while five years of explicitly modelled cash flow contributes the other 23.8%. The net-debt bar is the only step that is arithmetic rather than judgement. Look at the two heights before you argue about year-3 revenue growth.

The three things the output tells you that the five steps do not

Terminal value is 76.2% of the answer

Five years of forecasting — every margin, every capex assumption, the working-capital build, all of it — accounts for 23.8% of enterprise value. The remaining three quarters is one line: last year's cash flow, grown once, divided by WACC − g.

This reorders your priorities completely. Arguing about whether year-3 revenue growth is 6% or 7% moves the answer by a rounding error. Arguing about g moves it by tens of percent. And it explains why interviewers press on the terminal value and skip the forecast: they are pressing on the part that matters.

Two defensible inputs produce a 2.0x range

The grid moves WACC by ±1 point and g from 1.5% to 3.5% — every cell of which someone could argue for in a room. Corner to corner the implied share price runs from $16.52 to $33.43, a 2.0x spread.

That is the honest output of a DCF: a range with a shape, not a price. A candidate who answers "the DCF says $22.22" has told the interviewer they do not know how wide their own error bars are. The answer that scores is "$18 to $27 depending mostly on the terminal assumption, and here is which input I am least confident in".

Your growth rate already picked an exit multiple

This is the cross-check most candidates never volunteer, and it is the fastest way to catch yourself.

A perpetuity growth rate implies a terminal EV/EBITDA multiple, whether or not you compute it. Here, g = 2.5% at a WACC of 8.59% implies a terminal multiple of 8.7x — the terminal value of 2,899 over year-5 EBITDA of 334.4. If comparable mature companies in the industry trade at 6x, your "conservative" 2.5% growth rate has quietly assumed a 45% re-rating, and the model is not conservative at all.

The cell also runs the inversion: given a target exit multiple, solve for the g that produces it, then feed that g back through the valuation and print the resulting multiple. The round trip matching is the proof the inversion is right. It shows 8x implying g = 2.02%, 9x implying 2.71%, and 12x requiring 4.12% — well outside the 1%–3% convention the method is normally held to.

The refinement not worth your airtime

The mid-year convention discounts cash flow as if it arrives through the year rather than all on 31 December — year 1 at t = 0.5 instead of t = 1. It is more realistic, and the model shows it is worth +1.1% here: $22.22 becomes $22.47.

That is less than one column of the sensitivity grid. Knowing it exists is worth a sentence; spending two minutes on it while the terminal value sits unexamined is a misallocation the interviewer will notice. The general rule holds beyond this specific refinement: do not spend airtime on precision an order of magnitude smaller than your error bars.

What to change and re-run

  1. Set G = 0.01 and read the implied multiple. A "conservative" growth rate can imply a terminal multiple so low that it is its own kind of unreasonable. Conservatism has two edges.
  2. Set BETA = 1.6. Watch WACC rise, the denominator WACC − g widen, and the terminal value's share of enterprise value fall. Riskier companies have valuations less dominated by their terminal value, which is counterintuitive until you see it happen.
  3. Set CAPEX_PCT = DA_PCT. Capital spending equal to depreciation is the steady-state assumption the perpetuity formula implicitly wants; the forecast becomes internally consistent with its own terminal value, and free cash flow rises noticeably. Being able to say why those two should converge in the terminal year is a genuinely senior observation.

The next lesson builds the other model that gets asked about constantly, and it has the same structure of problem: a widely memorised rule of thumb that turns out to be a special case of something more general, and that breaks in a specific and predictable way.