> For the complete documentation index, see [llms.txt](https://dnotifier.gitbook.io/product-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://dnotifier.gitbook.io/product-docs/platform-guides/pure-dart.md).

# Pure Dart

The DNotifier Dart SDK is **pure Dart** — no Flutter dependency. Use it in CLI tools, Dart servers, scripts, and any Dart 3 project that needs realtime messaging, AI, or workflows without a UI framework.

## Requirements

| Requirement           | Version                                             |
| --------------------- | --------------------------------------------------- |
| Dart SDK              | 3.0 or later                                        |
| DNotifier credentials | From [app.dnotifier.com](https://app.dnotifier.com) |

→ [Install — Dart / Flutter](/product-docs/getting-started/installation/dart-flutter.md) (same package, skip Flutter steps)

***

## Create a Dart project

```bash
dart create my_dnotifier_service
cd my_dnotifier_service
```

Add to `pubspec.yaml`:

```yaml
name: my_dnotifier_service
environment:
  sdk: ">=3.0.0 <4.0.0"

dependencies:
  dnotifier: ^1.1.10
```

```bash
dart pub get
```

***

## WebSocket server or worker

Pure Dart on Linux, macOS, or Windows can hold persistent WebSocket connections — ideal for relay services, bots, and background workers.

```dart
import 'package:dnotifier/dnotifier.dart';

Future<void> main() async {
  final notifier = DNotifier(
    appId: const String.fromEnvironment('DNOTIFIER_APP_ID'),
    secret: const String.fromEnvironment('DNOTIFIER_SECRET'),
    transport: 'ws',
    userId: 'worker-1',
    onConnected: () => print('Worker connected'),
    onMessage: (DNotifierMessage msg) async {
      final job = msg.payload.toJSON();
      if (job is Map && job['type'] == 'task') {
        await notifier.send(
          senderId: 'worker-1',
          receiverId: msg.metadata.sender,
          data: {'type': 'result', 'status': 'done'},
        );
      }
    },
    onDisconnected: ({code, reason}) {
      print('Disconnected: $code $reason');
    },
  );

  await notifier.connect();

  // Keep process alive
  await Future<void>.delayed(const Duration(days: 365));
}
```

Run with defines:

```bash
dart run bin/worker.dart \
  --define=DNOTIFIER_APP_ID=your-app-id \
  --define=DNOTIFIER_SECRET=your-secret
```

{% hint style="info" %}
Unlike Node.js, Dart does **not** require a separate WebSocket package. The SDK uses `web_socket_channel` internally.
{% endhint %}

***

## HTTP transport for APIs and scripts

One-shot scripts and REST-style services use HTTP:

```dart
import 'package:dnotifier/dnotifier.dart';

Future<void> main() async {
  final notifier = DNotifier(
    appId: 'your-app-id',
    secret: 'your-app-secret',
    transport: 'http',
    userId: 'script-runner',
    onConnected: () {},
  );

  await notifier.connect();

  final response = await notifier.sendAI(
    senderId: 'script-runner',
    message: {'text': 'List three bullet points about Dart.'},
  );

  print(response);
}
```

→ [Choose your transport](/product-docs/getting-started/choose-transport.md)

***

## Environment configuration

### Compile-time defines

```dart
const appId = String.fromEnvironment('DNOTIFIER_APP_ID');
const secret = String.fromEnvironment('DNOTIFIER_SECRET');
```

```bash
dart run bin/main.dart --define=DNOTIFIER_APP_ID=... --define=DNOTIFIER_SECRET=...
```

### Runtime environment variables

For server deployments, read from `Platform.environment`:

```dart
import 'dart:io';

final appId = Platform.environment['DNOTIFIER_APP_ID'] ?? '';
final secret = Platform.environment['DNOTIFIER_SECRET'] ?? '';
```

Never commit secrets. Use your host's secret manager in production.

→ [Credentials & environment](/product-docs/getting-started/credentials.md)

***

## Knowledge base batch jobs

Index documents from the filesystem or a database:

```dart
await notifier.addDocument(
  senderId: 'indexer',
  recordId: 'doc-${file.hashCode}',
  content: await File(path).readAsString(),
  type: 'text',
  metadata: {'source': path},
);

final hits = await notifier.search(
  senderId: 'indexer',
  query: 'refund policy',
  limit: 5,
);
```

Use `transport: 'http'` and respect plan word limits.

→ [Manage documents](/product-docs/ai/manage-documents/dart-flutter.md)

***

## Workflows in Dart

```dart
final workflow = DNotifier.Workflow(
  name: 'daily-summary',
  observability: true,
  entry: (ctx) async {
    final ai = await ctx.sendAI(
      message: {'text': 'Summarize today\'s metrics.'},
      label: 'Summary',
    );
    return {'summary': ai};
  },
);

final run = await notifier.runWorkflow(
  workflow: workflow,
  input: null,
);
print(run.executionId);
print(run.result);
```

→ [Run a workflow](/product-docs/workflows-and-agents/run-workflow/dart-flutter.md)

***

## Concurrency

`DNotifier` is not isolate-safe. Use **one instance per isolate**:

| Pattern          | Guidance                                                |
| ---------------- | ------------------------------------------------------- |
| Single worker    | One `DNotifier`, one event loop                         |
| Multiple workers | One isolate per worker, each with its own `userId`      |
| `Isolate.spawn`  | Pass messages between isolates; do not share the client |

***

## Logging and observability

Enable SDK session logging for AI dashboard telemetry:

```dart
final notifier = DNotifier(
  // ...
  transport: 'http',
  logs: true,
);
```

Workflow observability is enabled per workflow with `observability: true`.

→ [Session logging](/product-docs/ai/session-logging/dart-flutter.md) · [Workflow observability](/product-docs/workflows-and-agents/observability.md)

***

## Deployment targets

| Target                           | Notes                                     |
| -------------------------------- | ----------------------------------------- |
| **VM (dart run / compiled exe)** | Full WebSocket and HTTP support           |
| **Docker**                       | Long-running `ws` services work well      |
| **Cloud Run / serverless**       | Prefer `http` for short-lived invocations |

{% hint style="warning" %}
Short-lived serverless runtimes are a poor fit for persistent `ws` connections. Use a dedicated VM or container for realtime, or `http` in serverless handlers.
{% endhint %}

***

## Pure Dart vs Flutter

| Feature      | Pure Dart                      | Flutter                          |
| ------------ | ------------------------------ | -------------------------------- |
| Package      | `dnotifier`                    | Same `dnotifier` package         |
| WebSocket    | ✅                              | ✅                                |
| UI lifecycle | Manual (signals, process exit) | `dispose()`, `AppLifecycleState` |
| Web target   | Dart web compiler              | Flutter Web                      |

If you add a UI later, the same SDK calls transfer to Flutter with minimal changes.

→ [Flutter platform guide](/product-docs/platform-guides/flutter.md)

***

## Next steps

* [Your first connection — Dart / Flutter](/product-docs/getting-started/first-connection/dart-flutter.md)
* [Node.js platform guide](/product-docs/platform-guides/nodejs.md) (JavaScript equivalent for servers)
* [Production checklist](/product-docs/operations/production-checklist.md)
