Guides / Gantt Chart Dependencies Explained: FS, SS, FF, SF

Gantt Chart Dependencies Explained: FS, SS, FF, SF

The four ways two tasks can depend on each other, and when to use each one.

Why dependencies are worth drawing at all

A Gantt chart without dependencies is a picture of dates. A Gantt chart with dependencies is a model of how the work actually fits together — and the difference shows up the moment something slips. Drag a task on a chart with no links and every other bar stays where it was, which is almost never true in reality. Drag a task on a linked chart and everything downstream moves with it, which is usually exactly what happens on the project.

That is the practical argument for spending ten minutes drawing arrows: it turns the chart from something you have to manually rewrite after every change into something that updates itself and tells you what the change cost.

Four ways two tasks can depend on each other

Most dependencies are Finish-to-Start: one task can't begin until the one before it ends. That covers a lot of real work, but not all of it. GanttFlow supports all four standard types.

Four lanes, each showing a different dependency type between two tasksFour lanes, each showing a different dependency type between two tasks

Finish-to-Start (FS). The second task starts when the first one finishes. This is the default, and it's the only type available on the Free plan.

Start-to-Start (SS). The second task starts when the first one starts. Useful for work that runs in parallel from the same kickoff point, like testing that begins alongside development rather than after it.

Finish-to-Finish (FF). The second task finishes when the first one finishes. Useful when two workstreams need to land together, even if they started at different times.

Start-to-Finish (SF). The second task finishes when the first one starts. This one is rare in practice: it fits situations like a handoff shift, where the outgoing task ends exactly when the incoming one begins.

When to use each type

The type you pick is a claim about the work, so it is worth being deliberate.

Reach for Finish-to-Start when the second task physically cannot begin until the first is complete. Concrete has to cure before steel goes up. A spec has to be signed off before it can be built against. If you are unsure, FS is the safe default — it is the most conservative reading, and a plan built entirely from FS links is pessimistic rather than wrong.

Reach for Start-to-Start when two pieces of work share a trigger but not a finish. This is the single most useful non-default type, because it is how most real parallelism gets modelled. A backend rewrite that begins when scope-locking begins. A native app build that starts once the web build is underway. Rough-in that begins while the envelope is still going up. Every one of these is a case where an FS link would add weeks to the plan that the team does not intend to spend.

Reach for Finish-to-Finish when two things must land together but started separately. Documentation finishing with the feature it documents. A training programme finishing when a system goes live. FF is about a shared deadline rather than a shared start.

Reach for Start-to-Finish almost never. It is included for completeness and it genuinely fits shift handovers and some just-in-time supply arrangements, but if you find yourself reaching for it on a normal project plan, it is worth checking whether you actually want an FF link drawn the other way round.

1

Select the dependency arrow

Click the arrow connecting two tasks. The settings panel shows a Dependency type field for that connection.

2

Choose a dependency type

Pick FS, SS, FF, or SF from the dropdown.

What a dependency does when dates move

The reason to get the type right is that it determines what happens when you drag something. An FS link moves the successor's start when the predecessor's finish moves. An SS link moves the successor's start when the predecessor's start moves — so pushing a predecessor's end date out has no effect on an SS successor at all, which surprises people the first time.

This is worth testing on your own chart before you rely on it. Drag a predecessor a week later and watch which downstream bars follow. If something moves that should not have, the link type is wrong. If something stays put that should have moved, the link is either missing or the wrong type.

The rescheduling guide covers how the cascade behaves in more detail, including what happens when a change ripples through several links at once.

What GanttFlow does not model

Worth being explicit, because most scheduling tools handle these and their absence changes how you build a plan:

There is no lag or lead on a dependency. You cannot say "start three days after this finishes." A dependency here is a direct relationship between two dates with no offset. When you need a gap — a curing period, a review window, a shipping delay — model it as its own task with its own bar. This is arguably better practice anyway: a named "concrete cure" bar is visible and questionable in a way that a hidden three-day lag value is not.

There is no automatic critical path calculation. GanttFlow will cascade changes through links, but it will not colour the critical path for you or compute float. On a chart of the size this tool is built for — a few dozen bars, readable on one screen — the critical path is usually the longest visible chain, and you can trace it. If you need computed float across hundreds of tasks, you need a scheduling engine, not a chart.

There is no resource levelling. Two tasks can overlap freely even if the same person is on both. The chart models sequence, not capacity.

Common mistakes with dependencies

Linking everything. A chart where every task connects to every other becomes a web of arrows nobody can read, and it makes the plan brittle — one slip visually cascades into everything. Link the relationships that are genuinely binding and leave the rest.

Using FS to mean "and then we do this." Sequence in your head is not the same as a constraint. If the second task could start earlier given the will and the people, an FS link is a scheduling decision disguised as a physical fact.

Modelling team contention as a dependency. When two tasks are sequential only because the same person does both, an arrow will produce a plan that looks constrained by the work when it is actually constrained by headcount. That is a resourcing conversation, and hiding it inside a dependency arrow prevents it from happening.

Forgetting to link milestones. Milestones can be dependency endpoints, which means a go-live marker can move automatically when the work leading into it slips. A milestone floating free of the tasks that produce it will happily sit on a date the plan can no longer hit.

Never testing the cascade. Draw the links, then drag something and watch. Five seconds of testing catches most wrong-type errors.

A quick way to sanity-check your links

Once the chart is drawn, pick the last milestone and trace backwards through the arrows to the start. That chain is your critical path. If the trace breaks — if you reach a task with no incoming link that clearly depends on something — you have found a missing dependency. If the trace loops, you have a circular reference that needs breaking.

Then drag the very first task a week later and see where the last milestone lands. If it moves a week, the model is consistent. If it does not move at all, your chart is a picture of dates after all, and it is worth finding out why before you present it.

Common questions

What is the most common dependency type in project management?
Finish-to-Start, by a wide margin. It covers any case where one task genuinely cannot begin until another is complete, which is the majority of real constraints. It is also the safest default: a plan built entirely from Finish-to-Start links is conservative rather than wrong, because it assumes no overlap anywhere.
Does GanttFlow support lag or lead time on dependencies?
No. A dependency links two dates directly with no offset, so you cannot express a rule like starting three days after something finishes. Model the gap as its own task instead - a named bar for a curing period, a review window, or a shipping delay. That is arguably better practice, since a visible bar can be questioned and a hidden lag value cannot.
Can a milestone be part of a dependency chain?
Yes, and it usually should be. Linking the last task in a chain to the milestone it produces means the milestone moves when the work slips. An unlinked milestone will sit on a date the plan can no longer hit, which is worse than having no milestone at all. The exception is a genuinely fixed external date, which should stay put deliberately.
How do I avoid a chart full of dependency arrows?
Only draw links that are binding. If the second task could start earlier given the will and the people, the relationship is a scheduling preference rather than a constraint, and drawing it makes the plan look more rigid than it is. Sequence that exists only because the same person does both tasks is a resourcing issue, not a dependency.
Why did my task not move when I dragged the one before it?
Almost always the wrong link type. A Start-to-Start link responds to the predecessor's start date, so pushing its end date later changes nothing downstream. Drag a predecessor and watch which bars follow - if something stays put that should have moved, the link is either missing or the wrong type.