Mastering Task Dependencies in Project Management (With Examples)
Most project schedules ignore dependencies. The few that include them only use one type. Here's the complete picture — what the four dependency types mean, when each applies, and which ones actually matter on real projects.
-->What "dependency" really means
In scheduling, a dependency is a constraint between two tasks: one can't (or shouldn't) happen until something happens with the other. The dependent task is the successor; the task it depends on is the predecessor.
The dependency captures which moment in the predecessor triggers which moment in the successor. There are four combinations.
The four dependency types
1. Finish-to-Start (FS) — the default
"Successor starts when predecessor finishes."
This is what 90% of dependencies are. Examples:
- Pour foundation → frame walls
- Write copy → design layout
- Approve design → start coding
- Send invitations → track RSVPs
If you can only learn one dependency type, learn this one. Most Gantt tools (including GanttBuilder) support FS as the default and primary relationship.
2. Start-to-Start (SS) — parallel kickoff
"Successor starts when predecessor starts."
The two tasks begin together but can finish at different times. Examples:
- Design discovery starts → user research starts (different methods, simultaneous)
- Excavation starts → erosion control starts (regulatory requirement)
- Recruiting starts → onboarding setup starts (HR prep in parallel)
When you'd use it: when two activities should happen at the same time, not one after the other, but you still want them linked so changes propagate.
3. Finish-to-Finish (FF) — coordinated completion
"Successor can't finish until predecessor finishes."
The successor runs in parallel but is blocked from completing until the predecessor wraps up. Examples:
- Testing finishes only when development finishes (testing keeps going as new code arrives)
- Documentation finishes only when the product finishes (docs evolve with the product)
- Final wedding-day prep finishes only when guests have arrived
FF is rare but powerful when you have an ongoing task that has to "wait for" something to settle before completing.
4. Start-to-Finish (SF) — the rarest
"Successor can't finish until predecessor starts."
Genuinely unusual. The textbook example: the new shift can't end until the old shift starts (you can't leave your post until your replacement arrives). Outside of staffing handovers, you'll almost never use it.
How to spot dependencies in real projects
Three questions for any two tasks:
- Can task B happen if task A hasn't started? If no → A is a predecessor
- Can task B finish if task A is still in progress? If no → consider FF
- Can task B start simultaneously with task A? If yes → consider SS
If none of the above feels right, the tasks are probably independent — and you should leave them that way. Over-constraining a schedule is as bad as under-constraining it.
What counts as a "real" dependency
Not all "this should happen before that" relationships are real dependencies. Distinguish:
Mandatory dependency (hard logic)
You physically can't do B without A. Pour concrete before placing rebar = impossible. Print invitations before designing them = impossible. These belong in the chart.
Discretionary dependency (preferred logic)
You'd prefer A before B, but it's not strictly required. Often a stylistic or risk choice. Include if the team agrees; exclude if it adds rigidity without value.
External dependency
Outside parties have to act. Permit approval, customer review, regulatory sign-off. Always include. Always allow extra buffer.
Resource dependency (fake)
"Tony can't do B because he's doing A." This is a resource conflict, not a logical dependency. Solve with scheduling, not predecessors.
Resource dependencies in a Gantt chart cause confusion: when Tony finishes A early, the chart still shows B starting at the old time. Better to model resource constraints separately.
-->Lag and lead times
A dependency can have a delay (lag) or an advance (lead):
- Lag: B starts N days after A finishes. Example: "Concrete cure" — pour finishes, then 7 days lag before framing starts.
- Lead: B starts N days before A finishes. Example: "Begin marketing 2 weeks before product launch."
Notation: FS + 7 (7-day lag), FS - 14 (14-day lead).
Lags are more common than leads. Many Gantt tools support both; GanttBuilder currently supports FS only without lag (workaround: insert a dummy "cure" task with appropriate duration).
Multiple predecessors
One task can have several predecessors. The successor starts when the latest predecessor finishes. Example:
- Integration testing waits for frontend complete AND backend complete
- Final inspection waits for electrical AND plumbing AND HVAC rough-in
- RSVPs final waits for invitations mailed AND response deadline
In GanttBuilder's CSV, list predecessors comma-separated: 5,8,12.
The critical path explained
Once dependencies are wired up, the critical path is the longest chain of dependent tasks from start to end. It determines the project end date.
Tasks on the critical path have zero slack — any slip propagates to the end date. Tasks off the critical path have slack: they can slip without affecting completion, up to a point.
Why this matters
- Focus your attention on critical path tasks. Speeding up a 5-day off-path task saves nothing; speeding up a 5-day on-path task saves 5 days.
- Hire help for the critical path. Adding people to off-path tasks rarely shortens delivery.
- Buffer the critical path. If you have schedule contingency, put it where it matters.
How to find it
Manual method:
- List all "paths" from start to end (chains of dependent tasks)
- Sum durations of each path
- The longest path is critical
Most professional tools compute this automatically. GanttBuilder doesn't yet (on the roadmap) but you can eyeball it: trace the longest chain of arrows from project start to project end.
Dependencies in agile projects
Agile teams often resist explicit dependency modeling, on the grounds that flexibility is the point. But even agile projects have hard dependencies:
- Authentication system must exist before user-specific features can be tested
- API contract must be defined before backend and frontend can parallelize
- Design system must be in place before consistent UI can ship
- Compliance review must happen before production launch
Capture these as Gantt-style dependencies between sprints, not within them. The intra-sprint work stays flexible.
Common dependency mistakes
1. Adding every possible dependency
Over-constrained schedules look impressive but lose all flexibility. Include only mandatory and high-value discretionary dependencies. Leave the rest out.
2. Modeling resource conflicts as dependencies
If two tasks compete for the same person, that's not a dependency — it's a scheduling problem. Resolve with explicit resource assignments.
3. Forgetting external dependencies
"Client review" is a task, not a footnote. If it takes 5 days, model it. If it's variable, add a buffer task.
4. Ignoring partial dependencies
Sometimes a successor can start when the predecessor is partially done. Use SS with lag, or split the predecessor into smaller tasks.
5. Inheriting summary-row dependencies
Don't make summary rows the predecessor of another task — the summary updates dynamically, which can cause weird cascades. Reference the actual leaf task.
Worked example
You're planning a software demo. Tasks:
- Write demo script (2 days)
- Build demo environment (3 days, independent)
- Practice run (1 day, needs both 1 and 2)
- Refine script based on practice (1 day, needs 3)
- Final demo (1 day, needs 4 and 2)
Dependencies:
- Task 3 has predecessors: 1, 2 (FS) — multiple predecessors
- Task 4 has predecessor: 3 (FS)
- Task 5 has predecessors: 4, 2 (FS) — though 2 is redundant since 4 already depends on 2 transitively
The critical path: write script → practice → refine → demo = 5 days. Environment building (3 days) has 2 days of slack.
-->