Project ManagementGantt ChartsPlanningDependencies

Gantt Chart Dependencies Explained: The 4 Types & Constraints

GanttPad Team··10 min read
← Back to blog

Dependencies are what separate a real project schedule from a list of tasks with dates. Without them, a Gantt chart is just a pretty calendar — bars on a timeline with no structural relationship to each other. If you're new to Gantt charts, how to make a Gantt chart walks through building your first one.

Most people understand the basic idea: Task B waits for Task A. But there are four distinct dependency types, and using only one of them — or using the wrong one — leads to schedules that either overstate the timeline or break on contact with reality.

What are dependencies in project scheduling?

A dependency (also called a logical relationship) is a constraint that ties one task's timing to another. It says: this task's start or finish is controlled by that task's start or finish.

Not every task that follows another task depends on it. Two tasks might happen in sequence simply because the same person does them — that's a resource constraint, not a logical dependency. A true dependency means the work itself requires the sequence, regardless of who does it. Pouring a foundation before framing walls isn't a staffing choice — it's physics.

Dependencies feed directly into critical path analysis, which identifies the longest chain of dependent tasks in your project. Without accurate dependencies, you can't determine which tasks govern the end date and which have room to slip.

The four dependency types

Every dependency connects a predecessor to a successor at either their start or finish point. This creates four possible combinations.

TypeAbbreviationMeaningHow common
Finish-to-StartFSB starts after A finishes~90% of dependencies
Start-to-StartSSB starts when A startsCommon
Finish-to-FinishFFB finishes when A finishesCommon
Start-to-FinishSFB finishes when A startsRare

Most project management tools — and most practitioners — default to FS for everything. That's reasonable as a starting point, but the other three exist for good reason.

Finish-to-Start (FS)

The successor cannot start until the predecessor finishes. This is the default dependency type and covers roughly 90% of real-world task relationships.

Construction example: The concrete slab must be poured and cured before framing begins. You cannot frame walls on a foundation that doesn't exist yet.

Software example: Backend API development must be complete before frontend integration testing can start. The tests need working endpoints to test against.

On a Gantt chart, FS shows as an arrow from the end of the predecessor bar to the start of the successor bar. When in doubt about which type to use, FS is almost always the right choice.

Start-to-Start (SS)

The successor can start once the predecessor starts — they run in parallel after that trigger point.

Construction example: Laying cable and inspecting cable. The inspection team doesn't wait for all cable to be laid — they start inspecting the first sections as soon as laying begins.

Software example: Writing documentation can begin once development starts. You don't need the finished product to start documenting the architecture, API design, or features already built.

SS is the dependency type teams most often miss. When two tasks genuinely can overlap but one triggers the other, SS compresses the schedule without removing the logical constraint. Using FS here would force the second task to wait unnecessarily, inflating the timeline.

Finish-to-Finish (FF)

The successor cannot finish until the predecessor finishes. Both tasks can run in parallel, but the successor's completion is gated by the predecessor's.

Software example: A user manual cannot be finalized until development is complete — the last round of edits depends on the final feature set.

Event planning example: Catering arrangements can't be finalized until the guest list is confirmed. The caterer needs a final headcount to place orders.

FF is common in documentation, QA sign-off, and any task where "finishing" requires the predecessor's final output. The work can overlap substantially, but the successor always trails by its dependency on the predecessor's endpoint.

Start-to-Finish (SF)

The successor cannot finish until the predecessor starts. This is the rarest dependency type.

Shift work example: The night security shift cannot end until the day shift starts. One shift covers until the next begins — the predecessor's start releases the successor.

Be honest with yourself: if you're using SF frequently, you've probably reversed the predecessor and successor. This is the most common modeling error with this type. Most real-world relationships that seem like SF are actually FS read in the wrong direction.

Leads and lags

Dependencies don't always mean "immediately." Real-world processes often include waiting time or allow overlap. That's where leads and lags come in.

Lag is a delay added to a dependency. In an FS relationship with a 3-day lag, the successor starts 3 days after the predecessor finishes — not immediately.

Lead is the opposite — an overlap. In an FS relationship with a 2-day lead, the successor starts 2 days before the predecessor finishes.

ModifierEffectExample
Lag (+2 days)Adds waiting time after the dependency is satisfiedConcrete curing, paint drying, client approval turnaround
Lead (−2 days)Starts the successor early, overlapping with the predecessorTesting early modules before all development finishes

Leads and lags apply to any dependency type, not just FS.

Leads are a powerful tool for compressing a schedule — they let you overlap tasks that technically have a sequential dependency. But they hide an assumption: that useful output from the predecessor is available before it officially finishes. If that assumption is wrong, the overlap creates a collision instead of a shortcut. Make the assumption explicit when you add a lead.

Dependencies vs constraints: two ways to control timing

A dependency ties a task to another task. A constraint ties a task to a date. Both control when work happens on a Gantt chart, and mixing them up is one of the quietest ways to break a schedule.

Most tools support some version of these constraint types:

ConstraintMeaningLegitimate use
As Soon As PossibleSchedule from dependencies alone — the defaultAlmost every task
Start No Earlier ThanCan't begin before a dateMaterial delivery, contract start date, site access
Must Start On / Must Finish OnPinned to a dateInspection appointments, event dates, regulatory deadlines
Deadline markerA visible target that doesn't move the scheduleClient promises you want on the chart without pinning the work

The decision rule: if the timing comes from the work, use a dependency; if it comes from the calendar, use a constraint. "Tile after the waterproofing cures" is a dependency with a lag. "The inspector comes Thursday" is a constraint — no amount of task-shuffling moves the inspector.

Constraints are also where schedules go rigid. Every hard "Must Start On" is a spot where the chart can no longer adjust itself: move a predecessor and, instead of flowing downstream, the change slams into the pinned date and turns into a conflict. A healthy schedule has many dependencies and a handful of constraints — the genuine fixed points, and nothing else. If you've pinned a task just to make the chart look the way you expect, delete the constraint and add the missing dependency instead.

How dependencies look on a Gantt chart

Dependencies appear as arrows connecting task bars. The arrow's attachment points tell you the type: an arrow from the end of one bar to the start of another is FS, from start to start is SS, and so on.

The real power shows up when you move things. Drag a predecessor bar to a later date, and every connected successor shifts automatically. This cascading effect is the entire point of modeling dependencies — the schedule stays logically consistent without manual recalculation.

A Gantt chart without dependency arrows is just a collection of bars on a timeline. The arrows are what make it a schedule.

Getting the task breakdown right is the prerequisite — dependencies connect the tasks you've already identified. If your breakdown is too coarse, you'll miss dependencies between sub-tasks. If it's too granular, you'll drown in arrows.

Common dependency mistakes

Using only FS when SS or FF would compress the schedule. Teams default to Finish-to-Start for everything because it's the simplest model. But when two tasks genuinely overlap — like development and documentation — forcing FS adds unnecessary time. Ask: does the successor truly need the predecessor to be completely finished, or just started?

Creating circular dependencies. A depends on B, B depends on C, C depends on A. The schedule becomes unsolvable. Most tools flag direct circles, but they can sneak in through indirect chains of five or six tasks. If your tool suddenly won't calculate dates, check for loops.

Over-linking tasks. Connecting every task to every related task creates a brittle schedule where any change cascades everywhere. Only add dependencies where there's a genuine logical constraint. "These tasks happen around the same time" is not a dependency.

Under-linking tasks. The opposite mistake: leaving tasks floating without connections. The schedule looks flexible but provides no useful sequencing information. Without dependencies, you can't identify the critical path or understand the impact of delays.

Confusing resource constraints with logical dependencies. "Sarah does both tasks" is a resource constraint, not a logical dependency. If a different person could do them in parallel, there's no finish-to-start relationship — there's a resource conflict. Modeling resource conflicts as dependencies distorts the critical path and inflates the timeline.

Pinning tasks to dates instead of linking them. Setting a hard start date on every task feels precise, but it freezes the schedule — when something moves, nothing follows automatically, and every date becomes a manual edit. Reserve date constraints for genuine fixed points; let dependencies drive everything else.

Ignoring leads and lags. Defaulting to zero lead and zero lag on every dependency when the real process includes waiting time or allows overlap. The schedule ends up either tighter or looser than reality — neither is useful for planning.

Getting dependencies right

Start with FS for everything — it's the safe default. Then review the schedule and ask where tasks genuinely overlap. Those are candidates for SS or FF. Add lags where real-world waiting time exists: curing, approvals, shipping. Question every SF — you probably don't need one. And keep date constraints down to the true fixed points.

Keep dependencies updated as the project evolves. When scope changes or tasks are re-sequenced, update the links. A stale dependency network is worse than none because it gives false confidence in dates that no longer reflect reality.

Dependencies are the structural skeleton of your schedule. They feed critical path analysis, resource planning, and schedule compression. Get them right, and the rest of your planning gets easier. Get them wrong, and every date in the project is suspect.