Gantt Chart Dependencies Explained: FS, SS, FF and SF
Four relationship types cover every dependency you can draw on a Gantt chart. One does about ninety per cent of the work; the other three exist for the cases it handles badly. Here is what each means, worked through one real project, plus the two things most explanations skip: lag versus lead, and total versus free float.
The project we will use throughout
Dependency diagrams are easy to nod along to and hard to apply. So: one real project — a billing system cutover — that every type below is applied to.
Replace the billing system. Six tasks, working days, March–April 2026.
| # | Task | Start | End | Days |
|---|---|---|---|---|
| 1 | Build the migration scripts | Mon 2 Mar | Fri 13 Mar | 10 days |
| 2 | Dry-run the migration | Mon 16 Mar | Fri 20 Mar | 5 days |
| 3 | Fix the defects the dry run finds | Mon 23 Mar | Fri 3 Apr | 10 days |
| 4 | Write the cutover runbook | Mon 16 Mar | Fri 3 Apr | 15 days |
| 5 | Train the billing team | Mon 23 Mar | Fri 27 Mar | 5 days |
| 6 | Keep the legacy system running | Mon 2 Mar | Mon 6 Apr | 26 days |
Six bars, no links yet — nothing here says what depends on what.
Finish-to-Start (FS) — the one you will use
Task B cannot start until task A finishes: pour the foundation, then frame the walls.
Task 2 is FS after task 1: you cannot dry-run a script nobody has written. Task 3 is FS after task 2, because the defect list does not exist until the dry run produces it. That chain — 1 → 2 → 3 — is the spine of the project and sets the 3 April finish.
FS is the default in every scheduling tool, and if you are unsure it is almost certainly right. Reaching for an exotic type usually means the tasks are wrongly broken down.
Start-to-Start (SS) — work that runs together
Task B cannot start until task A starts, and the two then run in parallel.
The runbook (task 4) is SS after the dry run. The writer needs the dry run underway to have anything to document, but waiting for it to finish would waste a week — so both begin Monday 16 March. The tell for SS is a shared trigger, not a shared deadline.
Finish-to-Finish (FF) — work that must land together
Task B cannot finish until A finishes.
The runbook also has an FF link to task 3: it cannot be signed off while defects are still landing, because each fix rewrites a step in it. So it stays open until Friday 3 April — started by the dry run, closed by the fixes, which is the shape of a support activity. Testing, documentation and QA sign-off are all FF for the same reason: B may start whenever, it just cannot cross the line first.
Start-to-Finish (SF) — the rare one
Task B cannot finish until task A starts. It reads backwards, and most planners never need it.
Task 6 is the case it was invented for. The legacy system must run until the new one is live: its finish is pinned to go-live's start. Link it SF and the legacy bar stretches to meet whatever date go-live lands on.
That is the test: a handover, where the outgoing thing ends because the incoming one begins. Anywhere else, reordering the tasks usually says the same thing with a plain FS.
The four types side by side
| Type | Real-world trigger | How often it applies | The mistake it invites |
|---|---|---|---|
| FS Finish → Start | A's output is B's input — a defect list, a signed drawing, a poured slab | ~90% of links | Used for preference, not constraint, until every date is pinned |
| SS Start → Start | Two activities share a trigger, then run together | Common; most plans have a few | Reacts only to the predecessor's start: if A's finish slips, B never moves |
| FF Finish → Finish | A wrapper that cannot close before the work it wraps — testing, docs, sign-off | Occasional, mostly support tasks | B's start left unconstrained, so it looks able to begin absurdly early |
| SF Start → Finish | A handover — the old shift or system ends because the new one begins | Rare; many correct plans have none | A clumsy backwards FS that reviewers misread |
When the wrong type makes the schedule lie
Now task 5, training. A planner links it SS after task 3: training starts when defect-fixing starts. It looks fine — both bars begin 23 March, everyone trained by 27 March, well before go-live.
Then the dry run finds more than expected. Task 3 grows from 10 days to 15, pushing its finish from Fri 3 Apr to Fri 10 Apr.
- Task 4 (runbook, FF) — moves. Its finish follows to Fri 10 Apr. Correct.
- Task 5 (training, SS) — does not move at all. SS watches the predecessor's start, and the start did not change. The plan still shows the team trained on Fri 27 Mar.
The chart is not broken; it is answering the question it was asked. But the team is now trained on software with a fortnight of defects still to land, and the plan reports that as green. The right link was FS after task 3. One wrong letter turned a two-week problem into no problem at all.
So test for it: extend the task most likely to overrun by a week, and see what moved. Anything you expected to shift and did not is a wrong type.
Lag and lead — a lag is a wait, not slack
A lag adds waiting time to a link. "FS + 3 days" means B starts three days after A finishes. Here, go-live is FS+1d after the defect fixes: one clear day for a final data sync.
The thing people get wrong: a lag is not slack. Slack is room you can spend when something slips. A lag is time already committed — concrete curing, paint drying, a contractual review window — and nobody gets to "use" it when they run late. Padding links with lag because a task "might" overrun creates contingency nobody can find or cut.
A lead is negative lag: "FS − 2 days" overlaps the tail of A. Leads compress a schedule — this is what fast-tracking is — but they buy time with risk. An overlap you have not reasoned about is a rework queue.
Both are written 3FS+2d — row 3, finish-to-start, two days lag — which gantts.app takes in the Runs after column.
Total float and free float are not the same number
Every task now has float: how long it can slip before it hurts something. There are two kinds, and confusing them is expensive.
Total float is how far a task can slip before the project finish moves. Free float is how far before its own successor moves. Free float is never larger.
Training has total float — the finish date is set by the defect chain. But total float is shared: if three tasks in a row each show eight days, there are eight days between them, not twenty-four. A lead who reads only that number and delays a week has spent float belonging to the whole chain.
Total float of zero is the definition of the critical path. Tick Critical path in gantts.app and that chain draws striped. That is where the types have to be right.
Creating and editing a dependency in gantts.app
- Drag from bar to bar. Grab the small dot at the edge of a task bar, drag onto the bar you want to link and release. The link is created as FS with zero lag.
- Change its type. Click the arrow between the bars. The link editor opens with a Type dropdown: FS · Finish → Start, SS · Start → Start, FF · Finish → Finish, SF · Start → Finish.
- Add a lag. Same editor, Lag (days) field:
1for the FS+1d before go-live, a negative number for a lead. Both undo with Ctrl+Z. - Or type it. The grid's Runs after column takes predecessors by row number:
3,2SS,3FF,3FS+2d, comma-separated. Fastest way to link a plan you just pasted in. - Or use the task card. Click a task, open Runs after (predecessors), and pick from the + Start this after… dropdown. Each existing link has its own type selector.
- Remove one. 🗑 Remove this link in the link editor, or the ✕ in the task card.
One behaviour worth knowing: adding a dependency here can only push a task later, never pull it earlier. The scheduler is "as-placed" — a task starts at the later of where you dragged it and where its predecessors allow. Link a task whose bar already sits well after its predecessor and nothing moves; the gap stays, because a bar you placed on purpose should not be yanked about by a link added for reporting. To compact everything, press ⚡ Auto-schedule, which pulls each dependent task back to the earliest date its predecessors allow, leaving unlinked tasks as anchors.
Templates that use this
- Project Management Gantt Chart Template
- Free Construction Gantt Chart Template
- Browse all Gantt chart templates
Keep reading
- Critical Path Method (CPM): Steps, Formula & Example
- What Is a Gantt Chart? Definition, Examples & Uses
- Baseline vs Actual: Tracking Schedule Variance on a Gantt Chart
Frequently asked questions
What are the 4 types of dependencies in a Gantt chart?
Finish-to-Start (FS), Start-to-Start (SS), Finish-to-Finish (FF) and Start-to-Finish (SF). FS covers the large majority of real relationships; SF is rare, and many plans need none.
What is the difference between lead and lag?
Lag is waiting time added to a link: FS+3d starts the successor three days after the predecessor finishes. Lead is negative lag, overlapping the two. A lag is committed time, not spare room.
What is the difference between total float and free float?
Total float is how far a task can slip before the project finish moves; free float is how far before its own successor moves. Total float is shared along a chain: three tasks each showing eight days do not have twenty-four between them.
Which dependency type should I use by default?
Finish-to-Start. If another type seems necessary, check whether the tasks are broken down correctly — an unusual type is often a symptom of a task that should be split.
What happens to my dates when I add a dependency in gantts.app?
A dependency can only push a task later, never pull it earlier: a task starts at the later of where you placed it and where its predecessors allow. Press ⚡ Auto-schedule to compact tasks back to their earliest legal dates.
How do I add dependencies in gantts.app?
Drag from the dot at the edge of a task bar onto another bar, or type notation such as 3FS+2d in the Runs after column. Click a link arrow to change its Type or Lag.