The term FFI stands for Foreign Function Interface, and it basically allows your Dart program to directly call functions and use data structures that exist in a compiled native library (.so, .dll, or .dylib file).
This is super useful when you need high-performance native code or when you want to reuse an existing C/C++ library instead of rewriting it in Dart.
For example, let’s say you have a simple C library that adds two numbers:
// add.c
int add(int a, int b) {
return a + b;
}
You’d compile this into a shared library, like libadd.so on Linux or Android. Then in Dart, you can use dart:ffi to load and call that function:
import 'dart:ffi' as ffi;
import 'dart:io';
typedef c_add_func = ffi.Int32 Function(ffi.Int32, ffi.Int32);
typedef dart_add_func = int Function(int, int);
void main() {
final dylib = ffi.DynamicLibrary.open('libadd.so');
final addPointer = dylib.lookupFunction('add');
final result = addPointer(10, 20);
print("Sum from native C code: $result");
}
Here’s what’s happening:
DynamicLibrary.open()loads the native shared library.lookupFunction()maps the C function to a Dart function type.- You can then call it just like any Dart function — but it executes in native machine code, which is much faster for certain operations.
In one of my experiments, I used dart:ffi to access a native C library for image processing — the operations were much faster than pure Dart implementations because they ran at native speed.
A challenge I faced was ensuring data type compatibility — Dart and C types don’t always match one-to-one, so you need to be careful about pointer handling and memory management. For instance, using ffi.Pointer and allocating/freeing memory correctly is crucial to avoid memory leaks or crashes.
The main limitation of dart:ffi is that it’s platform-dependent — you need to provide the correct shared library for each platform (Windows, macOS, Linux, Android, iOS). Also, debugging native crashes can be more complex than in pure Dart.
But overall, dart:ffi is an excellent tool when you need to:
- Call existing native C/C++ libraries,
- Improve performance of CPU-intensive operations, or
- Integrate with system-level APIs not exposed to Dart directly.
So in short — dart:ffi lets Dart talk directly to native code, giving you speed, flexibility, and native integration power, all while keeping your Dart app as the main control layer.
