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


# Project::level

Resolves resource overallocation in a [`Project`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/project/project.md>). It runs `solve(None)` with default options first, then writes persistent `leveling_delay` and `pauses` edits and accepts the leveled state as the baseline.

## Signature

```rust
pub fn level(&mut self, options: &LevelingOptions) -> Result<LevelingResult, Error>
```

Takes `&mut self`. Synchronous and CPU-only.

## Parameters

| Name | Type | Description |
|---|---|---|
| `options` | `&`[`LevelingOptions`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/resources/leveling-options.md>) | Scope, order, basis and how leveling may move tasks |

## Behavior

- Forward scheduling only.
- On a cyclic project, it returns the initial solve's result with `rounds: 0`.
- The leveled dates replace the baseline. To see leveling without committing it, call `level` on a [`clone`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/project/project.md#clone>).

## Returns

A [`LevelingResult`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/resources/leveling-result.md>).

## Errors

| Error | When |
|---|---|
| [`Error::Input`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/errors/error.md>) | An unknown id in `options.scope.resources` or `options.scope.tasks` (path `scope.resources` / `scope.tasks`); the project has `config.schedule_from_end: true` (path `config.schedule_from_end`) |
| [`Error::Project(ProjectError::NeedsResync)`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/errors/project-error.md>) | Returned by the initial solve |

## Example

Level two tasks that share one resource, first on a copy, then for real.

```rust
use plen_core::{
    AssignmentData, DateTime, LevelingOptions, Project, ProjectData, ResourceData, SolveOptions,
    TaskData,
};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let monday = DateTime::from_ymd_hm(2026, 8, 10, 8, 0).ok_or("invalid date")?;
    let task = |id: &str| TaskData {
        start_date: Some(monday),
        duration: Some(2.0),
        ..TaskData::new(id)
    };
    let assign = |task: &str| AssignmentData {
        id: None,
        task: task.into(),
        resource: "dev".into(),
        value: 1.0,
        offset: None,
        duration: None,
    };
    let data = ProjectData {
        tasks: vec![task("a"), task("b")],
        resources: vec![ResourceData { id: "dev".into(), capacity: None, calendar_id: None }],
        assignments: vec![assign("a"), assign("b")],
        ..Default::default()
    };

    let mut project = Project::default();
    project.solve(Some(data), &SolveOptions::default())?;

    // A proposal: level a cheap copy, the project keeps its dates.
    let mut draft = project.clone();
    let proposal = draft.level(&LevelingOptions::default())?;
    for update in &proposal.schedule.updates {
        println!("task {} delay {:?}", update.id, update.leveling_delay);
    }

    // Commit: level the project itself.
    let leveled = project.level(&LevelingOptions::default())?;
    println!("{} round(s)", leveled.rounds);
    Ok(())
}
```

## Related

- [`Project`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/project/project.md#level>) - the type and its other methods
- [`LevelingOptions`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/resources/leveling-options.md>) - scope, order, basis and step
- [`LevelingResult`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/resources/leveling-result.md>) - the returned result
- [Leveling Resources](<https://docs.dhtmlx.com/planning-engine/rust/resources-and-assignment/leveling-resources.md>) - how leveling works and its options
- [Preview leveling](<https://docs.dhtmlx.com/planning-engine/rust/how-to/preview-leveling.md>) and [Clear leveling](<https://docs.dhtmlx.com/planning-engine/rust/how-to/clear-leveling.md>) - step-by-step tasks
