{
"$type": "site.standard.document",
"bskyPostRef": {
"cid": "bafyreif4supjogqrsgoxv5vqsueowbz7qsf3iqtppsfokmwmfjcbydcrkm",
"uri": "at://did:plc:25rdn5elo5izoxrmtis34zuk/app.bsky.feed.post/3mok4hdvlfve2"
},
"coverImage": {
"$type": "blob",
"ref": {
"$link": "bafkreibcsjx3jrvkgkz2jzdnlyrw2uhdyjqgtlv3w4qqzsuke4n6qynw5e"
},
"mimeType": "image/webp",
"size": 141264
},
"path": "/codexlancers/flutter-file-uploads-made-easy-working-with-multipart-apis-3pgi",
"publishedAt": "2026-06-18T05:00:00.000Z",
"site": "https://dev.to",
"tags": [
"flutter",
"api"
],
"textContent": "File uploads are one of the most common requirements in real-world Flutter applications-whether it's uploading profile images, documents, or media files.\n\nAt **our company** , we've implemented file upload systems across multiple production apps, and one thing is clear:\n\nMost developers don't struggle with the concept-they struggle with clean implementation.\n\nIn this article, we'll break down **Multipart file uploads in Flutter using the latest stable packages** in a simple, production-ready way.\n\n## Why Multipart Requests Matter\n\nWhen sending data to APIs:\n\n * JSON works for text data\n * Files (images, PDFs, videos) require `multipart/form-data`\n\n\n\nThis format allows sending:\n\n * Normal fields (`userId`, `email`, etc.)\n * Files (binary data)\n\n\n\nin a single request.\n\n## Real-World Use Cases\n\nWe've used multipart uploads in:\n\n * Profile image uploads\n * KYC verification documents\n * E-commerce product images\n * Chat attachments\n * Resume uploads\n\n\n\n## Dependencies (Latest Versions)\n\n\n dependencies:\n http: ^1.6.0\n image_picker: ^1.2.1\n path: ^1.9.1\n\n\n## Step 1: Picking an Image\n\nWith the latest `image_picker`, the API remains stable while ensuring **null safety + proper typing**.\n\n\n\n import 'package:image_picker/image_picker.dart';\n\n final ImagePicker _picker = ImagePicker();\n\n Future<XFile?> pickImage() async {\n try {\n final XFile? image = await _picker.pickImage(\n source: ImageSource.gallery,\n imageQuality: 80,\n );\n\n return image;\n } catch (e) {\n print(\"Error picking image: $e\");\n return null;\n }\n }\n\n\n## Step 2: Multipart Upload Using http\n\nThe `http ^1.6.0` package still uses `MultipartRequest`, but we'll structure it more cleanly and safely.\n\n\n\n import 'dart:io';\n import 'package:http/http.dart' as http;\n import 'package:path/path.dart' as path;\n\n Future<void> uploadFile(XFile file) async {\n try {\n var uri = Uri.parse(\"https://yourapi.com/upload\");\n\n var request = http.MultipartRequest(\"POST\", uri);\n\n // Optional fields\n request.fields['userId'] = \"12345\";\n\n // File name handling\n String fileName = path.basename(file.path);\n\n // Attach file\n request.files.add(\n await http.MultipartFile.fromPath(\n 'file',\n file.path,\n filename: fileName,\n ),\n );\n\n // Send request\n var streamedResponse = await request.send();\n\n // Convert response stream\n var response = await http.Response.fromStream(streamedResponse);\n\n if (response.statusCode == 200) {\n print(\"Upload successful\");\n print(\"Response: ${response.body}\");\n } else {\n print(\"Upload failed: ${response.statusCode}\");\n print(\"Response: ${response.body}\");\n }\n } catch (e) {\n print(\"Upload error: $e\");\n }\n }\n\n\n## Step 3: UI Integration\n\n\n ElevatedButton(\n onPressed: () async {\n final file = await pickImage();\n\n if (file != null) {\n await uploadFile(file);\n }\n },\n child: const Text(\"Upload File\"),\n )\n\n\n## Important Validation (Production Ready)\n\nAlways validate file size before uploading:\n\n\n\n if (file.lengthSync() > 10 * 1024 * 1024) {\n print(\"File too large (Max 10MB allowed)\");\n return;\n }\n\n\n## What Changed in the Latest Approach?\n\nWith updated packages, best-practice improvements include:\n\n### ✔ Proper Response Conversion\n\n\n http.Response.fromStream(streamedResponse)\n\n\n### ✔ Safe Filename Extraction\n\n\n path.basename(file.path)\n\n\n## Common Mistakes Developers Still Make\n\n### 1. Not Converting Streamed Responses\n\nMultipart responses come as streams. Ignoring this often results in unreadable output.\n\n### 2. Missing Filename in Upload Requests\n\nSome servers reject files without explicit filenames.\n\n### 3. No Error Handling Around Image Picker\n\nImage selection can fail or be cancelled by the user.\n\n### 4. Uploading Oversized Files\n\nAlways validate file size before sending requests.\n\n## Best Practices We Follow\n\nAt scale, we always ensure:\n\n * Validate files before upload\n * Use proper filename handling\n * Convert response streams properly\n * Handle cancelled selections gracefully\n * Keep upload logic separated from UI\n * Use HTTPS only\n\n\n\n## Final Thoughts\n\nFile uploads in Flutter aren't complicated—but implementing them correctly makes a huge difference in production applications.\n\nOnce you understand how multipart requests work, the workflow becomes straightforward:\n\n 1. Pick a file\n 2. Attach it to a request\n 3. Send it securely to the server\n\n\n\nWith Flutter's latest stable packages like `http`, `image_picker`, and `path`, it's possible to build a clean and reliable upload system without unnecessary complexity.\n\nAt our company, this exact approach is used across multiple production apps where performance, maintainability, and reliability are critical.",
"title": "Flutter File Uploads Made Easy: Working with Multipart APIs"
}