The Dart Base64 API in dart:convert
Dart ships Base64 encoding in its core dart:convert library — no package install, no transitive dependencies. Available in every Dart target: Flutter mobile, Flutter web, server-side Dart (dart:io), and dart2js.
Four entry points you will actually use:
base64Encode(bytes)— top-level function, standard Base64 (RFC 4648 §4) with=padding.base64Decode(string)— top-level function, decodes standard Base64 back toUint8List.base64UrlEncode(bytes)— URL-safe variant using-and_instead of+and/.base64Url.decode(string)andbase64Url.normalize(string)— URL-safe decode and padding normalisation (handy for JWTs).
There are also the base64 and base64Url codecconstants (lowercase) that expose .encode(), .decode(),.encoder, and .decoder if you need to pipe through a Stream transformer. For 99% of cases, the top-level functions are fine.
Encoding a String
import 'dart:convert';
void main() {
final text = 'Hello 世界 👋';
// Step 1: Convert String to UTF-8 bytes
final List<int> utf8Bytes = utf8.encode(text);
// Step 2: Base64-encode the bytes
final String encoded = base64Encode(utf8Bytes);
print(encoded);
// Output: SGVsbG8g5LiW55WMIPCfkYs=
// One-liner
print(base64Encode(utf8.encode(text)));
}Dart Strings are UTF-16 under the hood but utf8.encode() produces the canonical UTF-8 byte sequence that every language agrees on. Never usetext.codeUnits for Base64 — it emits UTF-16 code units and the result is incompatible with Python, Go, Rust, etc.
Decoding Back to a String
import 'dart:convert';
String decodeToString(String encoded) {
final bytes = base64Decode(encoded);
return utf8.decode(bytes);
}
void main() {
final text = decodeToString('SGVsbG8g5LiW55WMIPCfkYs=');
print(text); // Hello 世界 👋
// With error handling
try {
final bytes = base64Decode('not valid base64!!!');
} on FormatException catch (e) {
print('decode failed: ${e.message}');
}
}Encoding an Image in Flutter
import 'dart:convert';
import 'dart:io';
import 'package:flutter/foundation.dart'; // compute()
import 'package:image_picker/image_picker.dart';
// Pattern 1: encode a file from disk (dart:io, mobile/desktop only)
Future<String> encodeFile(String path) async {
final bytes = await File(path).readAsBytes();
return base64Encode(bytes);
}
// Pattern 2: encode from image_picker (works on web and mobile)
Future<String?> pickAndEncodeImage() async {
final picker = ImagePicker();
final XFile? file = await picker.pickImage(source: ImageSource.gallery);
if (file == null) return null;
final bytes = await file.readAsBytes();
// For images over ~1 MB, do the encode in a background isolate
// so the UI stays at 60 FPS during the compute.
if (bytes.length > 1_000_000) {
return compute(_encodeInIsolate, bytes);
}
return base64Encode(bytes);
}
// Isolate-safe worker (must be top-level or static)
String _encodeInIsolate(List<int> bytes) => base64Encode(bytes);Displaying a Base64 Image in Flutter
import 'dart:convert';
import 'package:flutter/material.dart';
class Base64ImageView extends StatelessWidget {
final String encoded;
const Base64ImageView({super.key, required this.encoded});
@override
Widget build(BuildContext context) {
// Strip data URL prefix if present
final b64 = encoded.contains(',')
? encoded.split(',').last
: encoded;
try {
final bytes = base64Decode(b64);
return Image.memory(
bytes,
gaplessPlayback: true,
errorBuilder: (_, __, ___) => const Icon(Icons.broken_image),
);
} on FormatException {
return const Icon(Icons.error);
}
}
}URL-Safe Encoding for JWTs and URL Parameters
import 'dart:convert';
void main() {
final payload = utf8.encode('{"user_id":42,"role":"admin"}');
// Standard Base64 — uses + / and = padding
print(base64Encode(payload));
// eyJ1c2VyX2lkIjo0Miwicm9sZSI6ImFkbWluIn0=
// URL-safe — uses - _ and keeps = padding
print(base64UrlEncode(payload));
// eyJ1c2VyX2lkIjo0Miwicm9sZSI6ImFkbWluIn0=
// JWT style — URL-safe without = padding
String jwtEncode(List<int> bytes) =>
base64UrlEncode(bytes).replaceAll('=', '');
print(jwtEncode(payload));
// eyJ1c2VyX2lkIjo0Miwicm9sZSI6ImFkbWluIn0
// Decoding JWT segments — normalize restores missing padding
const jwtSegment = 'eyJ1c2VyX2lkIjo0Miwicm9sZSI6ImFkbWluIn0';
final padded = base64Url.normalize(jwtSegment);
final decoded = utf8.decode(base64Url.decode(padded));
print(decoded); // {"user_id":42,"role":"admin"}
}HTTP Basic Auth from Dart
import 'dart:convert';
import 'package:http/http.dart' as http;
String basicAuthHeader(String user, String password) {
final credentials = '$user:$password';
final token = base64Encode(utf8.encode(credentials));
return 'Basic $token';
}
Future<void> callProtectedApi() async {
final response = await http.get(
Uri.parse('https://api.example.com/protected'),
headers: {
'Authorization': basicAuthHeader('admin', 'secret123'),
'Accept': 'application/json',
},
);
print(response.statusCode);
print(response.body);
}Encoding a JSON Payload
import 'dart:convert';
void main() {
final data = {
'id': 42,
'email': '[email protected]',
'roles': ['admin', 'editor'],
'joined': '2026-01-15',
};
// Encode object → JSON string → UTF-8 bytes → Base64
final jsonString = jsonEncode(data);
final jsonBytes = utf8.encode(jsonString);
final encoded = base64Encode(jsonBytes);
print(encoded);
// Round-trip
final decoded = jsonDecode(utf8.decode(base64Decode(encoded)));
print(decoded);
}Streaming Encode for Large Files
import 'dart:convert';
import 'dart:io';
Future<void> streamEncode(String inputPath, String outputPath) async {
final input = File(inputPath).openRead();
final output = File(outputPath).openWrite();
// Chain: file bytes → base64 encoder → output file
await input
.transform(base64.encoder)
.transform(utf8.encoder) // base64.encoder emits String; we need bytes to write
.pipe(output);
await output.close();
}
// Note: for very large files, write Base64 line-wrapped (76 chars per line)
// using MimeMultipart's base64.encoder in line-wrap mode, or chunk manually.Flutter Web vs Flutter Mobile — Differences
- Flutter Web:
dart:iois not available. UseXFile.readAsBytes()from image_picker orhtml.FileReaderfor file uploads. The Base64 API itself is identical. - Flutter Mobile/Desktop: Full
dart:ioaccess —File(path).readAsBytes()works. Prefer asyncreadAsBytes()over syncreadAsBytesSync()to avoid blocking the UI isolate. - Flutter Server (dart:io): Same APIs as desktop. Use
Stream-basedbase64.encodertransformers for large payloads.
Common Pitfalls in Dart Base64 Code
- Passing a String to base64Encode — The function takes
List<int>, notString. The compiler will flag it, but if you cast withasyou will get a runtime type error. Always useutf8.encode(text)first. - Using codeUnits for text bytes —
text.codeUnitsemits UTF-16 code units. For non-ASCII input you will produce bytes that no other language decodes correctly. Useutf8.encode(text)instead. - Decoding unpadded URL-safe tokens — JWT segments drop the
=padding.base64Url.decode()throws FormatException on unpadded input. Callbase64Url.normalize(token)first to restore padding. - Blocking the UI isolate with large images — Encoding a 5 MB image on the main isolate drops frames for 100-300 ms. Use
compute(_encodeInIsolate, bytes)for anything over ~1 MB. Flutter will deliver the result on the main isolate when the compute completes. - Treating base64Encode output as safe for URLs — The default alphabet includes
+,/, and=which must be percent-encoded in URLs. Usebase64UrlEncode()when the output goes in a URL or JWT.
Command Line Alternative
For one-off encodes without writing Dart code, use the system base64CLI (macOS/Linux) or dart run with a scratch file:
# System base64
echo -n "Hello" | base64
# Dart one-liner (requires Dart SDK)
dart run -c "import 'dart:convert'; print(base64Encode(utf8.encode('Hello')));"
# Or save as b64.dart and run:
# import 'dart:convert';
# void main(List<String> args) => print(base64Encode(utf8.encode(args.first)));
dart run b64.dart HelloKey Facts
- Library:
- dart:convert — part of the Dart SDK, no package needed
- Standard encode:
- base64Encode(utf8.encode(text))
- URL-safe encode:
- base64UrlEncode(utf8.encode(text))
- Decode:
- utf8.decode(base64Decode(encoded))
- JWT padding fix:
- base64Url.normalize(token) before decode
- Large payloads:
- compute(_encodeInIsolate, bytes) for >1 MB
- Flutter Web:
- No dart:io — use XFile.readAsBytes()
- Error type:
- FormatException on invalid Base64 input
Related Base64 Tools
- Base64 Encode Online — general-purpose browser encoder
- Base64 Encode in JavaScript — Node.js and browser equivalent
- Base64 Encode in Swift — the iOS native counterpart to Flutter
- Base64 Encode in Kotlin — Android native counterpart to Flutter
- Base64 Encode Image — language-agnostic image encoder
- URL-Safe Base64 — cross-language URL encoding
- JWT Debugger — inspect JWT tokens