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


# Project#solve

Schedules a [`Project`](<https://docs.dhtmlx.com/planning-engine/js/api/project.md>) and accepts the scheduled dates as its baseline. Pass a [`ProjectData`](<https://docs.dhtmlx.com/planning-engine/js/api/types/project-data.md>) object to load a project, or `null` to reschedule after [`apply`](<https://docs.dhtmlx.com/planning-engine/js/api/project-apply.md>). [`preview`](<https://docs.dhtmlx.com/planning-engine/js/api/project-preview.md>), [`loadProfile`](<https://docs.dhtmlx.com/planning-engine/js/api/project-load-profile.md>), [`evaluate`](<https://docs.dhtmlx.com/planning-engine/js/api/project-evaluate.md>), [`slots`](<https://docs.dhtmlx.com/planning-engine/js/api/project-slots.md>) and [`suggestAssignments`](<https://docs.dhtmlx.com/planning-engine/js/api/project-suggest-assignments.md>) need a solved project.

For a one-shot run without keeping state, use [`schedule`](<https://docs.dhtmlx.com/planning-engine/js/api/schedule.md>).

## Signature

```ts
solve(data: ProjectData | null, options?: SolveOptions): ScheduleResult
```

Synchronous. Runs on the calling thread.

## Parameters

| Name | Type | Description |
|---|---|---|
| `data` | [`ProjectData`](<https://docs.dhtmlx.com/planning-engine/js/api/types/project-data.md>) \| `null` | Replacement data, or `null` to schedule the current state. `undefined` is treated as `null`. Never mutated. |
| `options` | [`SolveOptions`](<https://docs.dhtmlx.com/planning-engine/js/api/types/solve-options.md>) | Optional. Subtree, analytics and reporting switches. Default `{}`. |

## Behavior

- With `data`, the call validates the replacement data, installs it, schedules it and accepts the result. The previous data is discarded. How `data` is validated or repaired depends on the project's `validation` option (see [`Project`](<https://docs.dhtmlx.com/planning-engine/js/api/project.md>)).
- With `null`, the call schedules the current state when it has unsolved edits. When the project is already solved with equal `options`, it returns the cached result without scheduling again. The cache key is the whole `options` object.

Tasks touched by successful [`apply`](<https://docs.dhtmlx.com/planning-engine/js/api/project-apply.md>) calls since the last solve appear in `updates` as direct updates, even when the planner leaves them where the edit put them. A cyclic project returns unchanged dates and keeps those tasks pending.

The result's `baselineId` names the accepted baseline. It changes only when the data or the dates change, so solving an unchanged state keeps it.

## Returns

A [`ScheduleResult`](<https://docs.dhtmlx.com/planning-engine/js/api/types/schedule-result.md>). Each call returns a fresh object that shares nothing with `data` or the project, including a cached result. Date fields are strings, or local `Date` objects when the project was created with `dates: "date"`.

## Errors

| Error | When |
|---|---|
| [`InputError`](<https://docs.dhtmlx.com/planning-engine/js/api/types/errors.md>) | `data` or `options` fails parsing or validation; `kind`, `message` and `path` describe the problem. Also thrown for a non-finite number or an invalid `Date` in the input. The previous state and cached result are kept. |
| [`ProjectError`](<https://docs.dhtmlx.com/planning-engine/js/api/types/errors.md>) `"needs-resync"` | `data` is `null` after an `apply` rejected an operation and no `solve(data)` followed |
| `TypeError` | The input has a circular reference or a `BigInt`. |
| `Error("Project has been disposed")` | The project was disposed with [`dispose`](<https://docs.dhtmlx.com/planning-engine/js/api/project.md#dispose>). |

## Example

Load a project, commit an edit and reschedule it.

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

const project = new Project();
const loaded = project.solve({
  tasks: [{ id: "a", start_date: "2026-08-10 08:00", duration: 2 }],
});

// Nothing changed: the cached result comes back with the same baselineId.
const again = project.solve(null);
console.log(again.baselineId === loaded.baselineId); // true

project.apply({ tasks: { update: [{ id: "a", duration: 3 }] } });

const result = project.solve(null);
for (const update of result.updates) {
  console.log(`task ${update.id}: ${update.start_date} .. ${update.end_date}`);
  // task a: 2026-08-10 08:00 .. 2026-08-13 08:00
}
```

## Related

- [`Project`](<https://docs.dhtmlx.com/planning-engine/js/api/project.md>) - the class and its other methods
- [`SolveOptions`](<https://docs.dhtmlx.com/planning-engine/js/api/types/solve-options.md>) - the options
- [`ScheduleResult`](<https://docs.dhtmlx.com/planning-engine/js/api/types/schedule-result.md>) - the returned result
- [Errors](<https://docs.dhtmlx.com/planning-engine/js/api/types/errors.md>) - `InputError` and `ProjectError`
- [Scheduling a Project](<https://docs.dhtmlx.com/planning-engine/js/scheduling/scheduling-a-project.md>) - loading, caching and solve options
