# dart_openai: the unofficial OpenAI SDK for Dart and Flutter

> dart_openai wraps every major OpenAI API surface in typed Dart clients, and v8.0.0 adds web support, automatic retries and native Azure routing. It is aimed at Flutter teams that want one SDK instead of hand-rolled HTTP calls, and it stays unofficial by design.

**anasfik/openai** — The unofficial OpenAI SDK for Dart & Flutter. Full API coverage + OpenAI-compatible providers (Azure, DeepSeek, LM Studio, Ollama): Responses, Chat, Realtime, Videos, Batch, Fine-tuning.

- Repository: https://github.com/anasfik/openai
- Website: https://pub.dev/packages/dart_openai
- Stars: 666 · Forks: 231
- Language: Dart
- License: MIT
- Published: 2026-09-14 · Updated: 2026-09-14 · Language: en
- Canonical page: https://hysenlabs.com/projects/anasfik-openai

## What dart_openai solves for Flutter and Dart teams

Calling the OpenAI HTTP API from Dart means writing request bodies by hand, parsing JSON into models, decoding server-sent events, and mapping error payloads that differ between providers. dart_openai replaces that with typed clients. The README describes the package as an "Unofficial Dart/Flutter SDK for the OpenAI API" with typed clients for Responses, Chat Completions, Realtime, Videos, Batch, Fine-tuning, Vector Stores, Evals and Administration. The audience is narrow and specific: developers writing Flutter apps or server-side Dart who want the API surface expressed as Dart types rather than as maps. The README states it compiles and runs on Android, iOS, macOS, Linux, Windows, web and server-side Dart, which matters if the same code path has to run in a mobile app and in a backend job. It is unofficial, so nobody at OpenAI maintains it, and that single fact should shape how you evaluate the rest.

## One client object per provider, no global state

The core design decision in v8.0.0 is that every OpenAIClient owns its own configuration. In earlier versions the global facade was the entry point, and the README notes it still works: you can set OpenAI.apiKey and call OpenAI.instance.chat.create. The newer path lets several accounts, Azure resources or OpenAI-compatible providers run side by side. The README gives three constructions in one snippet: a production client with a plain key, a DeepSeek client with baseUrl set to https://api.deepseek.com, and a local Llama client pointed at http://localhost:1234/v1 with a placeholder key. That is the whole trick. Providers that implement the OpenAI wire format, which the README lists as DeepSeek, LM Studio, Ollama, Groq, Together and Azure OpenAI gateways, become interchangeable by changing a base URL. Configuration is per client: apiKey, organization, baseUrl, version, requestsTimeOut and extraHeaders. The trade-off is that you now pass the client around your codebase instead of reaching for a singleton, which is more plumbing but removes the class of bug where one test or one tenant overwrites another's key.

## Streaming, retries and the idle watchdog

The README states that one SSE engine backs every streaming endpoint, that it closes on [DONE], never duplicates events, and surfaces errors as exceptions rather than swallowing them. Two stream shapes are documented. The Responses API emits typed events you filter by name, and Chat Completions emits chunks with a delta. Retries are automatic on transient failures: connection errors and HTTP 408, 429 and 5xx. GET requests always retry, while POST retries only on rate limits and server errors, which is the conservative choice given that a duplicated POST can create a second job or a second charge. Backoff is exponential with jitter, and the README says the server's Retry-After header takes precedence. The default policy is two total attempts, and OpenAIRetryPolicy(maxAttempts: 4) raises it. Streaming also has an idle watchdog: a connection that stops delivering bytes fails with StreamTimedOutException after the request timeout. That is a real failure mode handled explicitly, and it is the kind of detail most hand-rolled clients miss.

## Installing dart_openai and making a first call

The package is published on pub.dev as dart_openai, and the README pins the current line at ^8.0.0. Add it to your pubspec and resolve.

```yaml
dependencies:
  dart_openai: ^8.0.0
```

```bash
dart pub get
```

Then construct a client and send a chat request. The README reads the key from the environment, which keeps it out of source control. The example model is gpt-4o and the call prints the first choice's content.

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

Future<void> main() async {
  final client = OpenAIClient(apiKey: Platform.environment['OPENAI_API_KEY']!);

  final completion = await client.chat.create(
    model: 'gpt-4o',
    messages: [
      const OpenAIChatCompletionChoiceMessageModel(
        role: OpenAIChatMessageRole.user,
        content: 'Say hello in five words.',
      ),
    ],
  );

  print(completion.choices.first.message.content);
}
```

For a streaming first run, the README shows the Chat Completions variant: call client.chat.createStream with the same model and messages, then await for each chunk and write chunk.choices.first.delta?.content to stdout. If you are targeting Azure instead, pass an OpenAIAzure object with resource, apiVersion and a deployments map, and the README states the model name is rewritten to your deployment automatically, so you keep calling with model: 'gpt-4o' while the client routes to the mapped deployment.

## Files, errors and what the client refuses to do

File uploads avoid dart:io on purpose. The README gives two paths: loadOpenAIFile from disk on native platforms, and file.uploadBytes with utf8-encoded bytes plus a fileName and purpose for anything that must also run on web. That is a deliberate constraint rather than an oversight, and it is the reason the same upload code compiles for a browser target. Error handling is typed. RequestFailedException carries message and statusCode for non-2xx responses, MissingApiKeyException covers a client with no key, and OpenAIUnexpectedException covers a malformed response that is not an API error payload. The README claims error payloads are normalized across providers, so a JSON error object, a bare string error or an HTML error page all arrive as a RequestFailedException with the body preserved. The clearest limitation is stated outright: Assistants v1 and Threads are not planned, because the README treats them as superseded by the Responses API. ChatKit is also not planned. If your existing code is built on Assistants, this package will not carry it forward, and that is a migration decision you have to make before adopting anything else here.

## How dart_openai compares to the official OpenAI SDKs

The obvious alternative is the official OpenAI client for your language. The official Python and JavaScript SDKs are maintained by OpenAI, track API changes as they ship, and come with vendor support channels. dart_openai is maintained by Anas Fikhi and is explicitly unofficial, so the difference is not features but ownership: who fixes it when OpenAI changes a response shape, and who you escalate to when it breaks in production. Language coverage is the other axis. If your backend is Python or Node, the official SDK is the lower-risk choice and dart_openai has nothing to offer you. The case for dart_openai is Dart and Flutter specifically, where the official SDKs do not run. Within that space, the multi-client design is the real differentiator: the README's ability to hold a DeepSeek client, a local LM Studio client and an Azure client in the same process, each with its own key, base URL and retry policy, is more than most thin HTTP wrappers attempt. The cost is that the package has to chase a fast-moving API surface on its own, and the changelog shows the pace: 6.0.0 in November 2025, then 7.0.0 and 8.0.0 in August 2026.

## Maintenance, licence and upgrade cost

The repository is not archived, and the last push was on 2026-08-25, the same day v8.0.0 and v7.0.0 were tagged. The prior major, 6.0.0, landed on 2025-11-08, so the gap between major lines has been measured in months rather than weeks. Major version bumps at this cadence mean upgrade work is a recurring cost, not a one-off: v8.0.0 changed the client model by introducing per-client configuration and native Azure support, which is the kind of change that touches every call site. The licence is MIT, which permits commercial and closed-source use and requires preserving the copyright notice and licence text; that is a summary of the identifier in the repository, not legal advice, and you should read the LICENSE file before shipping. Because the package is unofficial, no support agreement exists to buy. Your fallback is the source, which is Dart you can read and fork if a provider change lands faster than the maintainer can respond.

## Conclusion

Adopt dart_openai if your Flutter or server-side Dart code needs typed access to OpenAI and OpenAI-compatible endpoints, especially if you run several providers side by side or ship to web. Do not adopt it if you need Assistants v1 or Threads, which the README lists as not planned, or if you require a vendor-supported SDK with a support contract. Before committing, verify two things against your own account: that your target provider accepts the wire format the client sends, and that your pubspec resolves to 8.0.0, because the per-client OpenAIClient configuration and the Azure deployment mapping are the parts of the API you will build on.

## FAQ

### How do I install dart_openai?

Add dart_openai: ^8.0.0 to the dependencies block of your pubspec.yaml, then run dart pub get. The package is published on pub.dev under the name dart_openai.

### How do I use an OpenAI API key with dart_openai?

Pass the key to the OpenAIClient constructor, as the README does with Platform.environment['OPENAI_API_KEY']. The older global facade also accepts OpenAI.apiKey, and a client with no key throws MissingApiKeyException.

### How do I use the OpenAI API from dart_openai?

Construct an OpenAIClient and call the accessor for the surface you need, such as client.chat.create with a model and messages, or client.chat.createStream for streaming. The README lists typed accessors for Responses, Chat, Realtime, Videos, Batch, Fine-tuning and more.

## Sources

- [anasfik/openai on GitHub](https://github.com/anasfik/openai)
- [License: MIT](https://github.com/anasfik/openai/blob/main/LICENSE)
- [Project website](https://pub.dev/packages/dart_openai)
- [README](https://github.com/anasfik/openai/blob/main/README.md)
- [Releases](https://github.com/anasfik/openai/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/anasfik-openai
