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


# JsonProject.preview

Applies a change set to a copy of the solved baseline of a [`JsonProject`](<https://docs.dhtmlx.com/planning-engine/wasm/api/json-project.md>) and schedules the copy. The project isn't modified. Use it to show what an edit would do before committing it with [`apply`](<https://docs.dhtmlx.com/planning-engine/wasm/api/project-apply.md>). Needs a solved project with no edits applied since the last [`solve`](<https://docs.dhtmlx.com/planning-engine/wasm/api/project-solve.md>) or [`level`](<https://docs.dhtmlx.com/planning-engine/wasm/api/project-level.md>).

## Signature

```ts
preview(changes_json: string, options_json: string): string
```

Synchronous and read-only. Bad input comes back as an error envelope. The call doesn't throw.

## Request

| Argument | Payload | Required | Description |
|---|---|---|---|
| `changes_json` | [`SchedulingChanges`](<https://docs.dhtmlx.com/planning-engine/wasm/api/types/scheduling-changes.md>) | yes | The edits to try. `"{}"` previews no change |
| `options_json` | [`PreviewOptions`](<https://docs.dhtmlx.com/planning-engine/wasm/api/project-preview.md#previewoptions>) | yes | `"{}"` for defaults |

### PreviewOptions

The options object for `preview`. Every field can be omitted. Unknown fields, such as `includeUnchanged`, are rejected with a `parse` error.

| Field | Type | Required | Default | Description |
|---|---|---|---|---|
| `subtree` | [`Subtree`](<https://docs.dhtmlx.com/planning-engine/wasm/api/types/common.md#subtree>) | no | absent (whole project) | Previews only one branch. Same shape as `subtree` in [`SolveOptions`](<https://docs.dhtmlx.com/planning-engine/wasm/api/types/solve-options.md>) |
| `analytics` | [`AnalyticsOptions`](<https://docs.dhtmlx.com/planning-engine/wasm/api/types/common.md#analyticsoptions>) | no | none requested | Adds `analytics` for the previewed state. Same shape as `analytics` in [`SolveOptions`](<https://docs.dhtmlx.com/planning-engine/wasm/api/types/solve-options.md>) |
| `reasons` | boolean | no | `false` | Adds a `reason` to each update |
| `baselineId` | string | no | absent (not checked) | Must name the current baseline, or the call fails with `stale-baseline` |
| `profile` | [`ProfileQuery`](<https://docs.dhtmlx.com/planning-engine/wasm/api/types/common.md#profilequery>) | no | absent | Adds `profile`, the resource load of the previewed dates. Takes the fields of [`LoadProfileOptions`](<https://docs.dhtmlx.com/planning-engine/wasm/api/project-load-profile.md#loadprofileoptions>) except `baselineId`, which is an unknown field here |

`null` on any field reads as its default.

## Behavior

- `updates` are relative to the baseline. An empty change set gives empty `updates`.
- The result's `baselineId` is the baseline the preview read, so a following `preview` accepts it.
- The change set isn't partially accepted. One rejected operation fails the whole call.
- `options.baselineId` and `changes.baselineId` are checked separately. An absent token skips its check.
- The result stays sparse: there's no option to report unchanged tasks.

## Response

The success envelope carries a [`ScheduleResult`](<https://docs.dhtmlx.com/planning-engine/wasm/api/types/schedule-result.md>) for the previewed state. `profile` is present only when `options.profile` is set. Envelope shape: [Wire format](<https://docs.dhtmlx.com/planning-engine/wasm/wire-format.md#envelope>).

## Errors

| Kind | Code | When |
|---|---|---|
| `project` | `no-baseline` | The project has never been solved, or `apply` ran since the last solve |
| `project` | `stale-baseline` | `options.baselineId` or `changes.baselineId` doesn't name the current baseline |
| `validation` | `null` | An operation in `changes_json` is rejected (the error reports the first one, with its `path`, e.g. `tasks.update[0]`), or the `profile` query is invalid (e.g. `to` not after `from`, at `to`) |
| `parse` | `null` | Malformed JSON, or an unknown field in the change set or the options |

:::note
A start date that falls on non-working time is kept unsnapped when the task has no predecessor. The end is computed forward from it on the working calendar.
:::

## Example

Preview a resize of task `a` on a solved project, with reasons, guarded by the baseline token.

```js
const { JsonProject } = require("./pkg-node/plen_wasm.js");

const data = {
  config: { use_calendars: false },
  tasks: [
    { id: "a", start_date: "2026-01-01", duration: 2 },
    { id: "b", start_date: "2026-01-01", duration: 1 },
  ],
  links: [{ id: "ab", source: "a", target: "b" }],
};

const project = new JsonProject("{}");
try {
  const solved = JSON.parse(project.solve(JSON.stringify(data), "{}")).result;

  const changes = { tasks: { update: [{ id: "a", duration: 3 }] } };
  const options = { baselineId: solved.baselineId, reasons: true };
  const response = JSON.parse(
    project.preview(JSON.stringify(changes), JSON.stringify(options)),
  );

  if (response.ok) {
    for (const update of response.result.updates) {
      console.log(`${update.id}: ${update.start_date} .. ${update.end_date}`);
    }
    // a: 2026-01-01 00:00 .. 2026-01-04 00:00
    // b: 2026-01-04 00:00 .. 2026-01-05 00:00
  } else {
    const { kind, code, message, path } = response.error;
    console.error(kind, code, message, path);
  }
} finally {
  project.free();
}
```

`changes_json`:

```json
{ "tasks": { "update": [{ "id": "a", "duration": 3 }] } }
```

`options_json` (the token comes from the `solve` result):

```json
{ "baselineId": "1-b0605af8cba3d7c9", "reasons": true }
```

Response:

```json
{
  "ok": true,
  "result": {
    "baselineId": "1-b0605af8cba3d7c9",
    "conflicts": [],
    "converged": true,
    "cycles": [],
    "notes": [],
    "updates": [
      {
        "duration": 3,
        "end_date": "2026-01-04 00:00",
        "id": "a",
        "kind": "task",
        "reason": { "kind": "preferred" },
        "start_date": "2026-01-01 00:00"
      },
      {
        "end_date": "2026-01-05 00:00",
        "id": "b",
        "kind": "task",
        "reason": { "kind": "asap", "linkId": "ab", "sourceId": "a" },
        "start_date": "2026-01-04 00:00"
      }
    ]
  }
}
```

The project keeps its solved dates: `project.preview("{}", "{}")` still returns empty `updates`.

## Related

- [`SchedulingChanges`](<https://docs.dhtmlx.com/planning-engine/wasm/api/types/scheduling-changes.md>) - the change set to try
- [`ScheduleResult`](<https://docs.dhtmlx.com/planning-engine/wasm/api/types/schedule-result.md>) - the previewed result
- [`JsonProject.apply`](<https://docs.dhtmlx.com/planning-engine/wasm/api/project-apply.md>) - commit the change set once it looks right
- [Previewing Changes](<https://docs.dhtmlx.com/planning-engine/wasm/live-projects/previewing-changes.md>) - previews, clones and baseline tokens
- [Reading results](<https://docs.dhtmlx.com/planning-engine/wasm/scheduling/reading-results.md>) - reading updates, reasons and conflicts
