# Data Model

Gantt works with two main representations of task and link data:

- **Serialized**: JSON-compatible shapes with string dates, used in server responses, persisted JSON, and DataProcessor exchange
- **Runtime**: client-side objects with `Date` fields and computed `$`-prefixed properties, returned by methods like [gantt.getTask()](api/method/gettask.md) and [gantt.getLink()](api/method/getlink.md)

When you *provide* data to Gantt (rather than read it back), date fields may be either a `Date` or a `string`. The [`TaskInput`](#taskinput) type captures this lenient input shape, so you don't have to commit to `Task` or `SerializedTask` for data you author or hold in application state.

The canonical top-level payload passed to [gantt.parse()](api/method/parse.md) is `GanttData`.

Core runtime and serialized types are exported from `@dhx/gantt`. Wrapper packages re-export and consume these types in their public APIs, but the exact prop surface differs by wrapper.

## Data Lifecycle

Data flows through two transformations:

1. **Loading**: serialized task and link data is passed to `gantt.parse()` or `gantt.load()`. Gantt parses date strings into `Date` objects and adds computed `$`-prefixed properties, producing runtime `Task` and `Link` objects.
2. **Saving**: when changes are sent to the server via DataProcessor, dates are serialized back to strings and temporary `$`-prefixed fields are stripped.

See [Data Loading](guides/loading.md) and [Server-Side Integration](guides/server-side.md) for behavior details.

## SerializedTask

The JSON-compatible task shape. Date fields are strings, so this object can be safely passed through `JSON.stringify()` / `JSON.parse()`.

~~~ts
interface SerializedTask {
    id?: string | number;
    start_date?: string;
    end_date?: string;
    duration?: number;
    text?: any;
    type?: string;
    parent?: string | number;
    progress?: number;
    open?: boolean;

    auto_scheduling?: boolean;
    unscheduled?: boolean;
    constraint_date?: string;
    constraint_type?: string;
    deadline?: string;

    color?: string;
    textColor?: string;
    progressColor?: string;
    bar_height?: number;
    row_height?: number;
    hide_bar?: boolean;

    baselines?: SerializedBaseline[];
    calendar_id?: string | number;
    editable?: boolean;
    readonly?: boolean;
    render?: string;
    resource?: string[];
    rollup?: boolean;
    target?: string;

    [customProperty: string]: any;
}
~~~

For a meaningful scheduled task in serialized JSON, provide one valid scheduling combination:

- `start_date` + `duration`
- `start_date` + `end_date`
- `duration` + `end_date`

If `unscheduled: true`, dates can be omitted.

For detailed property descriptions, see [Task Properties](guides/task-properties.md).

## SerializedLink

~~~ts
interface SerializedLink {
    id: string | number;
    source: string | number;
    target: string | number;
    type: string;
    lag?: number;
    readonly?: boolean;
    editable?: boolean;

    [customProperty: string]: any;
}
~~~

For detailed property descriptions, see [Link Properties](guides/link-properties.md).

## Runtime Task and Link

After loading, Gantt stores tasks as runtime `Task` objects.

Main differences from `SerializedTask`:

- task date fields such as `start_date`, `end_date`, `constraint_date`, and `deadline` are JavaScript `Date` objects
- computed `$`-prefixed fields are added and maintained on the client

Common runtime-only task fields:

| Property | Type | Description |
|----------|------|-------------|
| `$index` | number | Global vertical position in the visible list |
| `$level` | number | Nesting depth in the task hierarchy |
| `$open` | boolean | Whether the branch is currently expanded |
| `$source` | Array | IDs of links going out of the task |
| `$target` | Array | IDs of links coming into the task |
| `$has_child` | boolean | Whether the task has child tasks |

The runtime `Link` object has the same field set as `SerializedLink`, but it is the client-side object returned by methods like `gantt.getLink()`.

For the full runtime lists, see [Task Properties](guides/task-properties.md#dynamic-properties) and [Link Properties](guides/link-properties.md).

## TaskInput

When you *provide* task data to Gantt - [gantt.parse()](api/method/parse.md), [gantt.addTask()](api/method/addtask.md), the `tasks` config/prop, or your own application store - use `TaskInput`. It is the lenient input shape: date fields accept either a `Date` or a `string`, and every field (including `id`) is optional, since Gantt generates an id when one is not supplied.

~~~ts
type TaskInput = Partial<SerializedTask> | Partial<Task>;
~~~

Use `TaskInput` for data you author or hold in application state. Use `Task` (runtime, `Date` dates, `$`-prefixed fields) when reading Gantt's own objects via methods like `gantt.getTask()`, and `SerializedTask` (string dates only) for JSON you exchange with a server.

~~~ts
// Application-owned task data handed to Gantt - either date form is accepted:
const tasks: TaskInput[] = [
    { id: 1, text: "Task #1", start_date: new Date(2026, 3, 1), duration: 5 },
    { id: 2, text: "Task #2", start_date: "2026-04-02", duration: 3 }
];
~~~

Storing application state as `TaskInput[]` is preferable to typing it as `SerializedTask[]` or `Task[]`: it avoids mismatches when your seed data uses `Date` objects but the type expects strings (or vice versa). Pick `Task` / `SerializedTask` only for the specific boundaries where the date representation is fixed.

## Supporting Types

### Baseline and SerializedBaseline

~~~ts
interface Baseline {
    id: string | number;
    task_id: string | number;
    start_date: Date;
    duration: number;
    end_date: Date;
    [customProperty: string]: any;
}

interface SerializedBaseline {
    id?: string | number;
    task_id?: string | number;
    start_date?: string;
    duration?: number;
    end_date?: string;
    [customProperty: string]: any;
}
~~~

### ResourceAssignment and SerializedResourceAssignment

~~~ts
interface ResourceAssignment {
    id: string | number;
    task_id: string | number;
    resource_id: string | number;
    value: number | string;
    delay: number;
    start_date: Date;
    end_date: Date;
    duration: number;
    mode: string;
    [customProperty: string]: any;
}

interface SerializedResourceAssignment {
    id?: string | number;
    task_id: string | number;
    resource_id: string | number;
    value?: number | string;
    mode?: string;
    delay?: number;
    start_date?: string;
    duration?: number;
    end_date?: string;
    [customProperty: string]: any;
}
~~~

### ResourceItem

~~~ts
interface ResourceItem {
    id: string | number;
    text?: string;
    parent?: string | number;
    open?: boolean;
    unit?: string | number;
    default_value?: string | number;
    [customProperty: string]: any;
}
~~~

See [Inbuilt Baselines](guides/inbuilt-baselines.md) and [Resource Management](guides/resource-management.md) for feature-specific details.

## GanttData

The object passed to [gantt.parse()](api/method/parse.md):

~~~ts
type GanttData =
  | {
      data: (SerializedTask | Task)[];
      tasks?: undefined;
      links?: (SerializedLink | Link)[];
      resources?: Partial<ResourceItem>[];
      assignments?: (SerializedResourceAssignment | ResourceAssignment)[];
      baselines?: (SerializedBaseline | Baseline)[];
      collections?: Record<string, Array<Record<string, unknown>>>;
    }
  | {
      tasks: (SerializedTask | Task)[];
      data?: undefined;
      links?: (SerializedLink | Link)[];
      resources?: Partial<ResourceItem>[];
      assignments?: (SerializedResourceAssignment | ResourceAssignment)[];
      baselines?: (SerializedBaseline | Baseline)[];
      collections?: Record<string, Array<Record<string, unknown>>>;
    };
~~~

Both `tasks` and `data` keys are accepted for the task array. `tasks` is preferred in new code.

~~~js
gantt.parse({
    tasks: [
        { id: 1, text: "Project #1", start_date: "2026-04-01", duration: 18 },
        { id: 2, text: "Task #1", start_date: "2026-04-02", duration: 8, parent: 1 }
    ],
    links: [
        { id: 1, source: 1, target: 2, type: "0" }
    ]
});
~~~

## Legacy Compatibility Aliases

Older API docs and typings still use several compatibility names:

- `DataToLoad1`, `DataToLoad2`: deprecated keyed variants of `GanttData`
- `NewTask`: legacy alias of [`TaskInput`](#taskinput) (defined as `TaskInput | string | {}`), kept for backward compatibility. Prefer `TaskInput` in new code.
- `NewResourceItem`: deprecated compatibility alias for `Partial<ResourceItem>`
- `NewAssignmentItem`: deprecated compatibility alias for `SerializedResourceAssignment | ResourceAssignment`

These names are kept for backward compatibility, but `GanttData`, `TaskInput`, `SerializedTask`, `SerializedLink`, `Task`, and `Link` are the canonical concepts used in this guide.

## Date Rules

- When exchanging JSON with the server, use strings for date fields
- If you build a JavaScript object directly and pass it to `gantt.parse()`, runtime task and assignment objects may contain `Date`
- After loading, Gantt stores task dates as `Date` objects in runtime `Task`
- Since v9.1.3, Gantt automatically detects ISO 8601 date strings

For details and examples, see [Data Loading - Loading Task Dates](guides/loading.md#loadingtaskdates).

## Custom Properties

All data types support custom properties via `[customProperty: string]: any`. Custom properties are preserved on the client side after loading and can be used in templates, columns, editors, and backend storage.

~~~js
gantt.parse({
    tasks: [
        {
            id: 1,
            text: "Task #1",
            start_date: "2026-04-01",
            duration: 10,
            priority: "high",
            owner: "John"
        }
    ],
    links: []
});

const task = gantt.getTask(1);
console.log(task.priority); // "high"
~~~

## Task Order

Gantt displays tasks in the order they appear in the `tasks` array. The position of each item in the array - together with the `parent` hierarchy - is the only thing that determines the visual order on the client. The runtime `$index` property is calculated from this array position and is not persisted.

This means the data source controls the display order. If users can [reorder tasks via drag-and-drop](guides/reordering-tasks.md), the data source needs a way to remember the new order so that subsequent loads return tasks in the correct sequence.

The standard approach is a numeric `sortorder` column in the backend storage. The data source sorts tasks by this column before returning them. `sortorder` is a backend-only concept - Gantt does not read or interpret it on the client. It travels as a [custom property](#custom-properties) if included in the payload, but has no built-in effect.

When a user reorders a task on the UI, Gantt populates the `target` property on the task object sent to the server via DataProcessor. The value indicates where the task was moved relative to its siblings:

- `target="taskId"` - place this task **before** the task with the given id
- `target="next:taskId"` - place this task **after** the task with the given id

The backend uses this value to recalculate `sortorder` for the affected tasks.

For the full implementation pattern - database schema, initial values, and reorder logic - see [Storing the Order of Tasks](guides/server-side.md#storingtheorderoftasks) in the Server-Side Integration guide. For client-side drag-and-drop configuration, see [Reordering Tasks](guides/reordering-tasks.md).
