Dart FFI: Calling C Code from Dart
Dart FFI is a bridge to the C world, letting you call native C libraries directly from Dart. Use it to access OS APIs or high-performance C/C++ code. The footgun: you must manually manage native memory, risking crashes or leaks if you forget to `free`.
WHY IT EXISTS Dart runs in its own managed environment with automatic memory management. However, most operating systems and countless high-performance libraries are written in C. FFI was created to bridge this gap, allowing Dart code to leverage this vast ecosystem of native code without rewriting everything from scratch.
THE MENTAL MODEL Think of Dart FFI as a translation layer or an adapter plug. Your Dart code speaks Dart, and a C library speaks C. FFI lets you define a contract in Dart—the function signature—that matches a function in the C library. It then handles the low-level details of calling that C function and marshalling data back and forth across the language boundary.
HOW IT WORKS The process involves three main steps. First, you load a native dynamic library (like a .so, .dll, or .dylib) into your Dart application. Second, you look up a specific function symbol within that library by its name. Third, you cast that symbol to a Dart function signature using dart:ffi types like Pointer, Int32, or Void. This gives you a callable Dart function that executes the underlying C code.
WHEN TO USE IT Use FFI when you need to interface with platform-specific native APIs (e.g., Win32 on Windows), integrate a high-performance C/C++ library for tasks like scientific computing or game physics, or reuse a critical piece of existing C code in a new Dart or Flutter application. The ffigen tool can automate generating the Dart bindings from C header files.
WHEN NOT TO USE IT Avoid FFI for simple logic that can be easily written in pure Dart. The overhead of managing memory and type conversions makes it unsuitable for trivial tasks. It is also not available for web applications, which run in a browser sandbox and require JS interop instead.
ONE CANONICAL EXAMPLE A common use is calling a simple C function. Imagine a C library with int32_t sum(int32_t a, int32_t b);. In Dart, you would load the library, look up the sum function, and define its type: final sum = dylib.lookup<NativeFunction<Int32 Function(Int32, Int32)>>('sum').asFunction<int Function(int, int)>();. Now you can call sum(2, 3) in Dart, and it will execute the native C code, returning 5.
Read the original → dart.dev
Get five bites like this every day.
Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.