Skip to content
Volume D · The TensorCore.si Library

Dart

One codebase for mobile, web and desktop with Flutter.

Dart is Google's language behind Flutter, the toolkit for building iOS, Android, web and desktop apps from one codebase. It is fast, null-safe and easy to learn, and packages like google_generative_ai and flutter_gemma bring AI into Flutter apps.

Prologue

Why learn Dart?

If you want to build beautiful cross-platform apps quickly, Dart and Flutter are among the most productive tools available.

  • Flutter: one codebase for iOS, Android, web, Windows, macOS and Linux.
  • Hot reload: see UI changes instantly while you code.
  • AI apps: call Gemini and other LLMs, or run small models on device.
Prologue

Set up and run your first program

Install the Flutter SDK, which includes Dart, or the standalone Dart SDK.

terminal
dart --version
dart create hello_ai && cd hello_ai
dart run
bin/hello_ai.dart
void main() {
  final name = 'Ada';
  print('Hello, AI! Welcome to Dart, $name.');
}
TipFor apps, run flutter create my_app and flutter run.
Chapter 1

Variables and null safety

var infers the type, final cannot be reassigned, const is a compile-time constant. A type with ? may be null; the compiler forces you to check.

variables.dart
void main() {
  var layers = 32;
  final model = 'llama3.1';
  const headDim = 128;
  double lr = 3e-4;
  String? note;                 // null by default
  print('$model: $layers layers, head $headDim, lr $lr');
  print(note ?? 'no note');
  print(note?.length);
}
Chapter 2

Control flow

Dart has if, for, for-in, while and modern switch expressions with patterns.

control.dart
void main() {
  for (var i = 0; i < 3; i++) print('epoch $i');
  for (final gpu in ['H100', 'B200']) print(gpu);
  const bits = 8;
  final name = switch (bits) {
    32 => 'FP32',
    16 => 'FP16',
    8 => 'FP8',
    _ => 'other',
  };
  print(name);
}
Chapter 3

Functions and collections

Functions support named and optional parameters and arrow syntax. Lists, sets and maps have rich methods like where and map.

functions.dart
int params({required int layers, int width = 4096}) => 12 * layers * width * width;

void main() {
  print(params(layers: 32));
  final vram = {'H100': 80, 'H200': 141, 'B200': 180};
  final big = vram.entries.where((e) => e.value > 100).map((e) => e.key).toList();
  print(big);
}
Chapter 4

Classes and records

Classes have concise constructors. Records group values without a class, and pattern matching can unpack them.

classes.dart
class Gpu {
  final String name;
  final int vramGb;
  const Gpu(this.name, this.vramGb);
  bool fits(double gb) => gb <= vramGb;
  @override
  String toString() => '$name ($vramGb GB)';
}

void main() {
  const g = Gpu('RTX 5090', 32);
  print('$g fits 16 GB: ' + g.fits(16).toString());
  final (name, gb) = ('B200', 180);   // record
  print('$name has $gb GB');
}
Chapter 5

Async, Futures and Streams

Network work returns a Future; use async/await. A Stream delivers many values over time, ideal for streaming AI responses.

async.dart
import 'dart:convert';
import 'package:http/http.dart' as http;   // dart pub add http

Future<void> main() async {
  try {
    final res = await http.get(Uri.parse('http://localhost:11434/api/tags'));
    final models = (jsonDecode(res.body)['models'] as List).map((m) => m['name']);
    print(models.toList());
  } catch (e) {
    print('Is Ollama running? $e');
  }
}
Part II · AI with Dart

AI with Dart and Flutter

Dart brings AI to apps on every platform: chat screens backed by Gemini or local models, on-device models with TensorFlow Lite or MediaPipe, and Firebase AI Logic for secure cloud calls.

The essential libraries

firebase_aiGemini models in Flutter via Firebase.
flutter_gemmaRun Gemma models on device.
tflite_flutterTensorFlow Lite inference in Flutter.
langchain_dartChains, RAG and agents for Dart.

Gradient descent from scratch

Learn y = 3x + 0.5 with loops.

gradient.dart
import 'dart:math';

void main() {
  final rng = Random(0);
  const n = 100;
  final xs = List.generate(n, (i) => -1 + 2 * i / (n - 1));
  final ys = xs.map((x) => 3 * x + 0.5 + (rng.nextDouble() - 0.5) * 0.2).toList();
  var w = 0.0, b = 0.0;
  const lr = 0.1;
  for (var step = 0; step < 500; step++) {
    var gw = 0.0, gb = 0.0;
    for (var i = 0; i < n; i++) {
      final err = w * xs[i] + b - ys[i];
      gw += 2 * err * xs[i] / n;
      gb += 2 * err / n;
    }
    w -= lr * gw;
    b -= lr * gb;
  }
  print('w=' + w.toStringAsFixed(2) + ' b=' + b.toStringAsFixed(2));
}
Part III · Build an AI agent

Build an AI agent in Dart

Using the http package and dart:convert, run the tool-calling loop against a local model. The same code works inside a Flutter app.

Your goal→Model plans→Tool call→Your code runs the tool→Result back to model→Final answer
agent.dart
import 'dart:convert';
import 'package:http/http.dart' as http;

String getWeather(String city) => 'It is 24°C and sunny in $city.';

Future<void> main() async {
  final tools = [
    {'type': 'function', 'function': {'name': 'get_weather', 'description': 'Weather for a city',
      'parameters': {'type': 'object', 'properties': {'city': {'type': 'string'}}, 'required': ['city']}}}
  ];
  final messages = <Map<String, dynamic>>[
    {'role': 'user', 'content': 'Should I take an umbrella in Lahore today?'}
  ];
  for (var round = 0; round < 5; round++) {
    final res = await http.post(Uri.parse('http://localhost:11434/v1/chat/completions'),
        headers: {'Content-Type': 'application/json'},
        body: jsonEncode({'model': 'llama3.1', 'messages': messages, 'tools': tools}));
    final msg = jsonDecode(res.body)['choices'][0]['message'] as Map<String, dynamic>;
    messages.add(msg);
    final calls = (msg['tool_calls'] as List?) ?? [];
    if (calls.isEmpty) { print(msg['content']); break; }
    for (final call in calls) {
      final args = jsonDecode(call['function']['arguments']);
      messages.add({'role': 'tool', 'tool_call_id': call['id'], 'content': getWeather(args['city'])});
    }
  }
}

On Android emulators, use 10.0.2.2 instead of localhost to reach a model on your computer.

Run it locallyInstall Ollama, run ollama pull llama3.1, and keep it running. The code talks to its OpenAI-compatible API at http://localhost:11434/v1, so the same program also works with vLLM, llama.cpp server or a cloud API by changing the URL, model name and adding an API key.
Part IV · Your path

Dart learning roadmap

Tick items off as you go. Your progress is saved in this browser.

Beginner

Intermediate

Advanced

Part IV · Your path

Projects to build

Flutter to-do appLists, state and local storage.
Weather appCall a REST API and show results.
AI chat appA Flutter chat UI backed by Gemini or a local model.
Reference

Dart cheat sheet

TaskSyntax
Variablefinal x = 1;
NullableString? s;
Interpolate'Hi $name'
List[1, 2, 3].map((x) => x * 2)
Asyncfinal r = await http.get(url);
Classclass P { final int x; P(this.x); }
Reference

Common mistakes

  • Using ! to force non-null throws if the value is null.
  • Forgetting await gives you a Future instead of the value.
  • Rebuilding large widget trees on every change slows Flutter apps; keep state local.
Reference

Where to go next

On TensorCore.si: Kotlin volume, Swift volume.

Keyboard: [ previous language · ] next language · / search the library