[Canonical page](<https://docs.dhtmlx.com/planning-engine/scheduling/>)
[Full documentation index](<https://docs.dhtmlx.com/planning-engine/llms.txt>)


# Scheduling work

Scheduling turns task relationships and working-time rules into dates. Planning Engine can build a plan from the anchors you supply, reschedule edited work, and tell you why tasks moved.

The result tells you when work can happen under the scheduling rules. Resource contention is reported alongside it, and you can deal with it separately through leveling or reassignment.

## What scheduling decides

The engine combines dependencies, calendars, project bounds, preferred dates, and enabled constraints. A task that waits for several predecessors has to satisfy all of those relationships. Then its working duration goes onto the relevant calendars.

In the [delivery example](<https://docs.dhtmlx.com/planning-engine/modeling.md#build-the-example-plan>), Design takes up Ann's Monday morning. Implement and Write guide both depend on Design, so both can start Monday afternoon. Review waits for Implement and runs on Ben's afternoon calendar.

There's no dependency between Implement and Write guide. Scheduling won't invent one just because Ann is assigned to both. That overload is a separate planning decision.

## Planning forward or backward

**Forward scheduling** places work at its earliest permitted dates. Starts and predecessors drive the plan. Use it when your question is "When can we finish if we start here?"

**Backward scheduling** places work at its latest permitted dates, working back from finishes and successors. Use it when your question is "When does work need to happen so we finish here?"

When constraints are enabled, a task can also have its own early or late scheduling preference that goes against the project's direction. A late task in a forward project can use the room before its successors instead of following its predecessors right away.

You still need to check whether a backward schedule works for your resources. The engine currently levels only forward-scheduled projects. Backward scheduling is there for date planning, not backward resource leveling.

## Preserving dates or closing gaps

Plans often have spacing on purpose. Say a task is reserved for Thursday even though its predecessor finishes Tuesday. The engine gives you two policies for dates like these.

**Preserve** treats existing dates as preferences and keeps gaps where scheduling allows. It's a good fit when you're making a local fix to an operational plan whose dates are already commitments.

**Compress** pulls placement tight against the scheduling bounds. A dependent task with an unneeded gap can move closer to its predecessor. That shows you an earlier feasible finish. An undriven task can still keep its explicit anchor, though.

For example, if Write guide starts out reserved for Wednesday, preserve can keep it there, while compress can bring it back to Monday afternoon after Design. Neither policy fixes Ann's overload on its own.

These policies also affect group movement and what happens after a series of edits. With preserve, the result can depend on the order in which you apply and schedule changes.

**API:** `SchedulingConfig` - [Rust](<https://docs.dhtmlx.com/planning-engine/rust/api/core/data/scheduling-config.md>) · [WASM](<https://docs.dhtmlx.com/planning-engine/wasm/api/types/scheduling-config.md>) · [JS](<https://docs.dhtmlx.com/planning-engine/js/api/types/scheduling-config.md>) · [.NET](<https://docs.dhtmlx.com/planning-engine/net/api/core/data/scheduling-config.md>) · [Java](<https://docs.dhtmlx.com/planning-engine/java/api/data/scheduling-config.md>)

## When requirements compete

Multiple dependencies combine into the strongest bound that applies. If a task has to follow two predecessors, the one that finishes later can set its start. Start-based and finish-based relationships can both add requirements.

When those requirements conflict, enabled hard constraints win. Say Implement finishes Tuesday at 12:00, but Review is constrained to start Monday at 13:00. The engine keeps the hard start requirement and reports that it disagrees with the dependency. Treat that output as evidence of an impossible combination. It doesn't mean reviewing unfinished work is fine.

Your application can then ask the user to relax the constraint, change the predecessor plan, or revise the dependency. A reported conflict doesn't make that business decision for them. With constraints disabled, those constraint dates don't affect scheduling at all.

## Scheduling groups and selected work

Summary dates usually follow their children. Moving Implement later can extend the delivery summary, even if nobody edited the summary directly.

With preservation and group movement enabled, dependencies can move a summary's descendants together and keep their relative layout where allowed. Fixed and completed children stay protected, and pinned children keep their constraint restrictions. So the group doesn't have to move like a rigid rectangle.

With group movement disabled, or when you compress, summary relationships expand into relationships on the leaves. Scheduling then works through the group's tasks instead of shifting the whole block.

A manual summary with explicit dates keeps its own span, but its children aren't automatically held inside it. If you need containment, put a real finish constraint on the relevant work.

You can also start scheduling from a selected subtree. The engine takes its successors into account and reads connected tasks outside the selection at their accepted dates. So the selection isn't an isolated project: dependent work and ancestor summaries can show up in the result too.

**API:** `Subtree` - [Rust](<https://docs.dhtmlx.com/planning-engine/rust/api/core/project/subtree.md>) · [WASM](<https://docs.dhtmlx.com/planning-engine/wasm/api/types/common.md#subtree>) · [JS](<https://docs.dhtmlx.com/planning-engine/js/api/types/common.md#subtree>) · [.NET](<https://docs.dhtmlx.com/planning-engine/net/api/core/project/subtree.md>) · [Java](<https://docs.dhtmlx.com/planning-engine/java/api/project/subtree.md>)

## Reading the result

Here's the compressed dependency schedule for the example:

| Task | Start | Finish | Why |
|---|---|---|---|
| Design | Monday 08:00 | Monday 12:00 | Supplied starting anchor |
| Implement | Monday 13:00 | Tuesday 12:00 | Follows Design; fits eight working hours on Ann's calendar |
| Write guide | Monday 13:00 | Monday 17:00 | Follows Design; fits four working hours |
| Review | Tuesday 13:00 | Tuesday 17:00 | Follows Implement; Ben works afternoons |
| Ready to release | Tuesday 17:00 | Tuesday 17:00 | Waits for both Review and Write guide |

If Review started out on Monday, scheduling moves it to Tuesday. If the guide started out reserved for Wednesday, compression can move it earlier. The result usually holds the changed task properties, not a full replacement plan. If you want the complete normalized date list, your application can request it on solve.

Movement explanations can point to a driving dependency, constraint, preferred date, or summary translation. Show the updated summary dates in your application's plan too.

**API:** `solve` - [Rust](<https://docs.dhtmlx.com/planning-engine/rust/api/project-solve.md>) · [WASM](<https://docs.dhtmlx.com/planning-engine/wasm/api/project-solve.md>) · [JS](<https://docs.dhtmlx.com/planning-engine/js/api/project-solve.md>) · [.NET](<https://docs.dhtmlx.com/planning-engine/net/api/project-solve.md>) · [Java](<https://docs.dhtmlx.com/planning-engine/java/api/project-solve.md>)

### Cycles, conflicts, and convergence

Three diagnostics answer different questions:

| Diagnostic | Meaning | Consequence |
|---|---|---|
| Cycle | Dependencies and structural relationships form a loop. | Scheduling aborts without moving dates; the cycle identifies the tasks and links to inspect. |
| Conflict | Scheduling requirements disagree, such as a hard date versus a dependency. | A plan can still be returned, with the disagreement recorded. |
| Nonconvergence | The scheduling process did not settle within its configured iteration limit. | Returned dates should not be treated as a fully settled plan. |

An empty update list can mean nothing needed to move. It can also come with a run that aborted on a cycle. Always read diagnostics and convergence along with the dates.

**API:** `ScheduleResult` - [Rust](<https://docs.dhtmlx.com/planning-engine/rust/api/core/results/schedule-result.md>) · [WASM](<https://docs.dhtmlx.com/planning-engine/wasm/api/types/schedule-result.md>) · [JS](<https://docs.dhtmlx.com/planning-engine/js/api/types/schedule-result.md>) · [.NET](<https://docs.dhtmlx.com/planning-engine/net/api/core/results/schedule-result.md>) · [Java](<https://docs.dhtmlx.com/planning-engine/java/api/results/schedule-result.md>)

### Critical work and slack

**Total slack** is how far a task can move later under the scheduling model before it hits its late bound. **Free slack** is how far it can move without affecting its successors. The two can differ: a task can have room before the project finish while any movement at all pushes the next task.

Critical work has no positive total slack. The engine can report critical tasks and driving links, so your application can highlight the work the schedule is sensitive to. Negative slack means there's pressure beyond the available bounds.

In the example, Design → Implement → Review sets the release date. The guide finishes earlier and has room before the release milestone. You might use that room to fix Ann's overload without extending the project.

Slack covers dependencies, calendars, and scheduling constraints. It doesn't reserve resource capacity. A task with lots of slack can still have nowhere to go without pushing someone else's work aside. The engine uses one project-end anchor for critical-path analysis. It doesn't calculate a separate critical path for each independent chain.

Analysis can also inspect supplied or current dates without rescheduling them. That's handy when your application wants diagnostics on the plan as shown, not a proposed new placement.

**API:** `analyze` - [Rust](<https://docs.dhtmlx.com/planning-engine/rust/api/project-analyze.md>) · [WASM](<https://docs.dhtmlx.com/planning-engine/wasm/api/project-analyze.md>) · [JS](<https://docs.dhtmlx.com/planning-engine/js/api/project-analyze.md>) · [.NET](<https://docs.dhtmlx.com/planning-engine/net/api/project-analyze.md>) · [Java](<https://docs.dhtmlx.com/planning-engine/java/api/project-analyze.md>)

## Continue with resource planning

The example finishes Tuesday, but Ann is booked twice on Monday afternoon. You have at least two ways to fix that: move one task into free time, or give it to another eligible person.

[Resolving resource overload](<https://docs.dhtmlx.com/planning-engine/resource-planning.md>) covers the first approach. [Exploring better plans](<https://docs.dhtmlx.com/planning-engine/planning-alternatives.md>) covers comparing alternatives and choosing assignments.
