{
  "$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"
}