Quick answer
To convert cURL to Dart, build the request with the http package: Uri.parse() the URL, pass the -H values as a headers map, encode a JSON body with jsonEncode, and use http.MultipartRequest for -F uploads. Paste a cURL command into Playxoft's free cURL to Dart converter to get runnable code for http or Dio, laid out the way dart format would, that drops straight into a Flutter app.
- http or Dio
- dart format layout
- JSON, forms and multipart
- Timeouts, -k and proxies
- Credential warnings
- Flutter ready
How to use the cURL to Dart Converter
- 1Paste a command into cURL command, or choose one from Load example.
- 2Choose http or Dio.
- 3Keep Check status on so error responses throw instead of passing silently.
- 4Check Parsed request and the notes, especially for -k and proxies, which work on mobile, desktop and servers but not on the web.
- 5Add the package with
flutter pub add http(ordio), then copy the code or download request.dart.
cURL flags cheat sheet: what does each option become in Dart?
| cURL | package:http | Dio |
|---|---|---|
| The URL | Uri.parse('…') | The URL string |
-X POST | http.post(…) | dio.post(…) |
-H "Name: value" | headers: {'Name': 'value'} | Options(headers: {…}) |
| A JSON body | body: jsonEncode({…}) | data: {…} |
-d "a=1&b=2" | body: {'a': '1', 'b': '2'} | data: {…} with a form content type |
-F file=@a.png | http.MultipartRequest with MultipartFile.fromPath | FormData.fromMap with MultipartFile.fromFile |
-u user:pass | An Authorization: Basic header | Same |
-m 30 | .timeout(const Duration(seconds: 30)) | receiveTimeout (per-chunk idle time; wrap the call in .timeout() for a hard cap) |
--connect-timeout 5 | HttpClient.connectionTimeout | connectTimeout |
-k | badCertificateCallback on an HttpClient | The same, through IOHttpClientAdapter |
-x host:8080 | findProxy on an HttpClient | The same, through IOHttpClientAdapter |
The http package sends a Map<String, String> body as an HTML form and sets that content type itself. A String body is sent as is, so JSON needs both jsonEncode and a JSON Content-Type header. Dio encodes maps as JSON unless you ask for a form.
http vs Dio: which should you use in Flutter?
| http | Dio | |
|---|---|---|
| Maintainer | The Dart team | The community (cfug) |
| Error responses | Returned like any other response | Throw a DioException |
| Timeouts | Future.timeout on each call | Connect, send and receive timeouts |
| Interceptors | Wrap the client yourself | Built in |
| Uploads | MultipartRequest | FormData with progress callbacks |
| Cancelling | AbortableRequest with an abortTrigger (http 1.5+) | CancelToken |
Start with http: it is small, maintained by the Dart team and enough for most apps. Reach for Dio when many calls need the same interceptors (token refresh, logging, retries), or when you want upload progress built in.
How do I use the converted code in a Flutter app?
The generated code runs as is with dart run. To use it in Flutter:
- Add the package:
flutter pub add http(ordio). Multipart uploads with a content type also needflutter pub add http_parser. - Move the body of
main()into an async method, such asFuture<User> fetchUser(), and call it from aFutureBuilderor your state management. - On Android, release builds need the internet permission in
AndroidManifest.xml:<uses-permission android:name="android.permission.INTERNET" />. Debug builds include it automatically. - On macOS, enable the
com.apple.security.network.cliententitlement. - Prefer https URLs: Android 9 and later block plain http traffic by default.
Code that reads a File or creates its own HttpClient (for -k, proxies or connect timeouts) depends on dart:io, so it doesn't run on Flutter web.
How do I handle errors and retries with Dio?
Dio throws a DioException for timeouts, connection failures and, by default, any status outside 2xx. Its type tells you which one happened, so you can decide what is worth retrying:
try {
final response = await dio.get('https://api.example.com/v1/orders');
print(response.data);
} on DioException catch (e) {
if (e.type == DioExceptionType.badResponse) {
print('HTTP ${e.response?.statusCode}: ${e.response?.data}');
} else if (e.type == DioExceptionType.connectionTimeout ||
e.type == DioExceptionType.receiveTimeout) {
print('Timed out; safe to retry a GET');
} else {
rethrow;
}
}Dio doesn't retry on its own. Add a retry interceptor (the dio_smart_retry package is one) or loop with a short delay, and retry only idempotent requests such as GET, PUT and DELETE unless the API supports idempotency keys. Create one Dio instance with your base URL, headers and interceptors and reuse it across the app, rather than calling Dio() per request.
Copying requests from a browser? See how to copy as cURL in Chrome or Firefox DevTools. Browser copies carry headers a mobile app never sends, such as sec-ch-ua and origin: turn on Drop browser headers for the sec-* group and delete origin and referer unless the API checks them.
Can I ship API keys copied from a cURL command in a Flutter app?
No. Anything compiled into an app can be pulled out of the APK or IPA, so a key in your Dart code is effectively public. Keep secrets on a server you control and have the app call it, or use short-lived tokens issued to each user after sign-in.
The converter itself is private: it runs in your browser and never uploads your command. While testing, read values from the environment: $API_TOKEN in the command becomes Platform.environment['API_TOKEN']! in the generated Dart. That suits scripts; Flutter apps usually pass build-time values with --dart-define, which are not secret either.
The Contains credentials badge flags anything still hard-coded, and a badCertificateCallback that returns true must never reach a release build.
Frequently asked questions
Last updated by the Playxoft engineering team.