> ## Documentation Index
> [HTML page](https://blode.co/stratasync/docs/guides/load-strategies)
> [Documentation index](https://blode.co/stratasync/docs/llms.txt)
> Use the index to discover all available pages before exploring further.

# Load strategies

Control when and how model data is fetched from the server with instant, lazy, partial, and other strategies.

Set per model via `@ClientModel`. Controls bootstrap timing, transfer volume, and offline availability.

## Decision tree

```mermaid
flowchart TD
    A[Does this model need to sync with the server?]
    A -->|No| B["local"]
    A -->|Yes| C[Is the data needed on every page load?]
    C -->|Yes| D[Is the total dataset small?]
    D -->|Yes| E["instant"]
    D -->|No| F["partial"]
    C -->|No| G[Should it load automatically when accessed?]
    G -->|Yes| H["lazy"]
    G -->|No| I["explicitlyRequested"]
```

## Strategy reference

| Strategy              | Behavior                                                                               | Best for                                                                   | Trade-off                                                                   |
| --------------------- | -------------------------------------------------------------------------------------- | -------------------------------------------------------------------------- | --------------------------------------------------------------------------- |
| `instant`             | Bootstrap includes all instances; data available from first render                     | Small, always-needed models (users, teams, labels)                         | Adds to bootstrap payload size                                              |
| `lazy`                | Not included in bootstrap; fetched on first access via hooks or relationship traversal | Models needed only on some pages (attachments, activity feeds)             | First access has network latency; only accessed instances available offline |
| `partial`             | Loads a relevant subset at bootstrap; fetches remaining instances on demand            | High-volume models where only a slice matters (comments, notifications)    | Requires partial index tracking in IndexedDB                                |
| `explicitlyRequested` | Never auto-loaded; fetched only via `client.get()` or `client.query()`                 | Large or sensitive models loaded on specific pages (audit logs, analytics) | No data present until you request it                                        |
| `local`               | Never synced; stored only in IndexedDB and the in-memory identity map                  | Client-only state (drafts, UI preferences, unsent messages)                | No server backup or cross-device access                                     |

## Code examples

Set the strategy in the `@ClientModel` decorator.

### instant

```ts
@ClientModel("User", { loadStrategy: "instant" })
export class User extends Model {
  /* ... */
}
```

### lazy

```ts
@ClientModel("Attachment", { loadStrategy: "lazy" })
export class Attachment extends Model {
  /* ... */
}
```

### partial

```ts
@ClientModel("Comment", {
  loadStrategy: "partial",
  partialLoadMode: "regular",
})
export class Comment extends Model {
  /* ... */
}
```

Partial load modes control bootstrap priority:

| Mode          | Behavior                                                     |
| ------------- | ------------------------------------------------------------ |
| `full`        | Load the complete subset during bootstrap (highest priority) |
| `regular`     | Load the subset at normal priority                           |
| `lowPriority` | Load the subset after higher-priority models                 |

### explicitlyRequested

```ts
@ClientModel("AuditLog", { loadStrategy: "explicitlyRequested" })
export class AuditLog extends Model {
  /* ... */
}
```

### local

```ts
@ClientModel("DraftMessage", { loadStrategy: "local" })
export class DraftMessage extends Model {
  /* ... */
}
```

## Quick reference table

| Model type         | Example             | Strategy               | Reasoning                    |
| ------------------ | ------------------- | ---------------------- | ---------------------------- |
| Core entities      | User, Team, Project | `instant`              | Always needed, small dataset |
| Primary work items | Task                | `instant` or `partial` | Depends on volume            |
| Secondary content  | Comment, Attachment | `partial` or `lazy`    | Only needed in context       |
| Large datasets     | AuditLog, Analytics | `explicitlyRequested`  | Loaded on specific pages     |
| Sensitive data     | AdminSettings       | `explicitlyRequested`  | Access-controlled            |
| Client-only state  | Draft, UIPreference | `local`                | Never synced                 |

## Server-granted coverage

A server can widen a client's partial-index coverage mid-stream by emitting a
`"C"` (covering) sync action naming a model, an indexed key, and a key value.

The rows behind a newly covered key are not carried in the delta stream, so the
client batch-loads them and only then records the coverage. Recording coverage
first would leave `loadByIndex` reporting a complete — but empty — set for that
key, with nothing to trigger a repair.

The fetch runs after the packet is applied, so a `"C"` action never blocks the
rest of the packet.

## Identity map eviction

The identity map applies an LRU ceiling (`identityMapMaxSize`, default 10,000 rows
per model) to bound memory.

Only **demand-loadable** models are evicted. `instant` models are declared to sync
in full and `ensureModel()` refuses to refetch them, so evicting one would silently
shrink every query against it until the next bootstrap. `local` models never sync,
so the in-memory copy is the only copy. Both are exempt, whatever the ceiling.

`lazy`, `partial`, and `explicitlyRequested` models are evictable: each can be
fetched again on next access, and eviction emits a `modelChange` so hooks re-render
and Suspense re-hydrates.

This means a large `instant` model is held in memory in full. If that is too much,
the fix is to move it to `partial` or `lazy` — not to lower the ceiling.

## Performance implications

- **Bootstrap payload size**: Includes all `instant` models and `partial` subsets. If slow, move large models to `partial`/`lazy`, limit via `prefetchBootstrap`, or enable compression.
- **Identity map memory**: Every loaded instance stays in memory. Use `partial` for high-volume models.
- **Delta stream filtering**: Deltas arrive for all accessible models but apply only for loaded instances. `local` models never receive deltas.

## Complete example

All five strategies in a task management app:

```ts
// Always loaded -- small dataset
@ClientModel("User", { loadStrategy: "instant" })
export class User extends Model {
  /* ... */
}

// Always loaded -- core work items
@ClientModel("Task", { loadStrategy: "instant" })
export class Task extends Model {
  /* ... */
}

// Partially loaded -- fetch comments for viewed tasks
@ClientModel("Comment", {
  loadStrategy: "partial",
  partialLoadMode: "regular",
  usedForPartialIndexes: true,
})
export class Comment extends Model {
  /* ... */
}

// Only loaded when explicitly requested
@ClientModel("AuditLog", { loadStrategy: "explicitlyRequested" })
export class AuditLog extends Model {
  /* ... */
}

// Local-only draft state
@ClientModel("CommentDraft", { loadStrategy: "local" })
export class CommentDraft extends Model {
  /* ... */
}
```

### Bootstrap flow for mixed strategies

The server streams `instant` models first, then `partial` subsets, skipping `explicitlyRequested` and `local`. The client then opens a delta stream and fetches more on demand.

```mermaid
sequenceDiagram
    participant Client
    participant Server

    Client->>Server: Bootstrap request
    Note over Server: Stream instant models
    Server-->>Client: All User rows
    Server-->>Client: All Task rows
    Note over Server: Stream partial models
    Server-->>Client: Comment rows (for user's sync groups)
    Note over Server: Skip explicitlyRequested and local
    Server-->>Client: Metadata (lastSyncId, groups)

    Note over Client: Seed IndexedDB + identity map
    Client->>Server: Open delta stream from lastSyncId

    Note over Client: Later, user views a task
    Client->>Server: Batch load: Comments where taskId = X
    Server-->>Client: Comment rows for task X
    Note over Client: Update partial index coverage
```