Multipart HTTP uploads carry files in named form fields. curl sends a local file as multipart/form-data using the file-field name required by the HTTP endpoint. For uploads from PHP code, use PHP cURL multipart form data.

In cURL, each --form option becomes one multipart section. Prefix the local path with @ to send that part as a file upload, keep the field name before the equals sign aligned with the API contract, and append ;type=... when the server validates the part MIME type.

Most failures come from using the wrong field name, sending a raw request body to an endpoint that expects multipart form data, or treating a text field as a file part. Use --form only for browser-style file uploads; raw-body APIs belong to --data-binary, while remote transfer targets such as FTP, SFTP, or PUT uploads use different cURL modes.

Steps to upload a file with curl multipart form data:

  1. Send a local file as one multipart form field.
    $ curl --form "file=@release-manifest.txt" https://httpbin.org/post
    {
      "args": {},
      ##### snipped #####
      "url": "https://httpbin.org/post",
      "data": "",
      "files": {
        "file": "Quarterly release manifest\n"
      },
      "form": {},
      ##### snipped #####
    }

    The httpbin.org test service is public and echoes the upload back, so a private file belongs only on your own endpoint. Replace release-manifest.txt with the real local path and https://httpbin.org/post with the real upload URL when the upload is not a test.

    The field name is the text before the equals sign. Append ;filename=release-manifest.txt;type=text/plain when the endpoint validates the uploaded filename or MIME type.

    Use a different upload mode only when the server expects a raw request body or a remote transfer target instead of a browser-style form.
    Related: Send a file as one raw request body
    Related: Upload files to FTP or SFTP with cURL

  2. Add text fields in the same request when the API expects metadata beside the uploaded file.
    $ curl --form "file=@release-manifest.txt" --form "description=Quarterly release manifest" https://httpbin.org/post
    {
      "args": {},
      ##### snipped #####
      "url": "https://httpbin.org/post",
      "data": "",
      "files": {
        "file": "Quarterly release manifest\n"
      },
      "form": {
        "description": "Quarterly release manifest"
      },
      ##### snipped #####
    }

    Use --form-string instead of --form when a literal text value might begin with @ or < or include ;type=.

    A successful multipart upload should show a response body that names the expected file field.

Share this guide