[Canonical page](<https://docs.dhtmlx.com/planning-engine/js/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/js/api/project.md>). It first runs `solve(null)` with default options, then writes `leveling_delay` and `pauses` on tasks and accepts the leveled state as the new baseline. Use it after loading data or after [`apply`](<https://docs.dhtmlx.com/planning-engine/js/api/project-apply.md>), in place of `solve(null)`.

## Signature

```ts
level(options?: LevelingOptions): LevelingResult
```

Synchronous. Runs on the calling thread, so a long run blocks the event loop.

## Parameters

| Name | Type | Description |
|---|---|---|
| `options` | [`LevelingOptions`](<https://docs.dhtmlx.com/planning-engine/js/api/types/leveling-options.md>) | Optional. Scope, order, basis and how leveling may move tasks. Default `{}`: the whole project with default settings. |

## Behavior

- Forward scheduling only.
- The leveled dates, delays and pauses replace the baseline, and the project is marked solved. To see leveling without committing it, call `level` on a [`clone()`](<https://docs.dhtmlx.com/planning-engine/js/api/project.md#clone>).
- `level` never changes assignments.
- On a cyclic project, it returns the initial solve's result with `rounds: 0` and edits no delay or pause.
- `updates` are relative to the state the call started from, so they can be applied to the task list the caller already holds. They include `leveling_delay` and `pauses` changes, and edits made by earlier `apply` calls.

For how leveling picks tasks to delay or split, see [Leveling Resources](<https://docs.dhtmlx.com/planning-engine/js/resources-and-assignment/leveling-resources.md>).

## Returns

A [`LevelingResult`](<https://docs.dhtmlx.com/planning-engine/js/api/project-level.md#levelingresult>): a fresh object that shares nothing with the project.

### LevelingResult

Every field of [`ScheduleResult`](<https://docs.dhtmlx.com/planning-engine/js/api/types/schedule-result.md>), taken from the final solve, plus one field:

| Field | Type | Description |
|---|---|---|
| `rounds` | `number` | Number of leveling rounds that proposed a correction. `0` when nothing was overallocated or the project has cycles. |

:::note
The leveling result is a `ScheduleResult` with an added `rounds` field; read `updates` on it.
:::

## Errors

| Error | When |
|---|---|
| [`InputError`](<https://docs.dhtmlx.com/planning-engine/js/api/types/errors.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`); an unknown option key or a bad option value; a non-finite number or an invalid `Date` in `options`. |
| [`ProjectError`](<https://docs.dhtmlx.com/planning-engine/js/api/types/errors.md>) `"needs-resync"` | An earlier `apply` had rejected operations and no full `solve(data)` has run since. |
| `Error("Project has been disposed")` | The project was disposed. |

## Example

Two tasks share one resource. Level a copy first, then the project itself.

```js
import { Project } from "plen-js";

const project = new Project();
project.solve({
  tasks: [
    { id: "a", start_date: "2026-08-10 08:00", duration: 2 },
    { id: "b", start_date: "2026-08-10 08:00", duration: 2 },
  ],
  resources: [{ id: "dev" }],
  assignments: [
    { task: "a", resource: "dev", value: 1 },
    { task: "b", resource: "dev", value: 1 },
  ],
});

// Preview: level a copy, the project keeps its dates.
const proposal = project.clone().level();
for (const update of proposal.updates) {
  console.log(`task ${update.id} delay ${update.leveling_delay}`);
}

// Commit: level the project itself.
const leveled = project.level();
console.log(`${leveled.rounds} round(s)`);
```

## Related

- [`Project`](<https://docs.dhtmlx.com/planning-engine/js/api/project.md#clone>) - `clone` for previewing leveling
- [`LevelingOptions`](<https://docs.dhtmlx.com/planning-engine/js/api/types/leveling-options.md>) - the options
- [`Overallocation`](<https://docs.dhtmlx.com/planning-engine/js/api/types/overallocation.md>) - windows left after leveling
- [Leveling Resources](<https://docs.dhtmlx.com/planning-engine/js/resources-and-assignment/leveling-resources.md>) - how leveling works and its options
- [Preview leveling](<https://docs.dhtmlx.com/planning-engine/js/how-to/preview-leveling.md>) - level a clone before committing
