# Handling File Uploads with Multipart Form Data

**URL:** <https://forums.swift.org/t/handling-file-uploads-with-multipart-form-data/84808>\
**Category:** Vapor\
**Created:** [February 19, 2026, 8:24am UTC](https://forums.swift.org/t/handling-file-uploads-with-multipart-form-data/84808 "2026-02-19T08:24:41Z")\
**Posts on this page:** 14\
**Page:** 1

<div class="post-metadata">

**Author:** ![simon68](https://avatars.discourse-cdn.com/v4/letter/s/9d8465/32.png) [@simon68](https://forums.swift.org/u/simon68)\
**Post date:** [February 19, 2026, 8:24am UTC](https://forums.swift.org/t/handling-file-uploads-with-multipart-form-data/84808/1 "2026-02-19T08:24:41Z")

</div>

Hi,

I am trying to create a route to upload a file in the `Public/uploads` directory of my App. For this purpose I added the `multipart-kit` to my package.

Here is my route:

```swift
    app.post("upload") { req async throws -> String in
        let file = try req.content.decode(File.self)
        guard file.filename.hasSuffix(".jpg") || file.filename.hasSuffix(".png") else {
            throw Abort(.badRequest, reason: "Only JPG or PNG files allowed")
        }
        let path = req.application.directory.publicDirectory.appending(file.filename)
        try await req.fileio.writeFile(file.data, at: path)
        return "Uploaded file: \(file.filename)"
    }

```

I have a file `appicon.png` stored in the project root directory. But when I try to test the route with curl :

`curl -X POST http://127.0.0.1:8080/upload -F file=@appicon.png`

I get the following error :

> No such key 'data' at path ''. No value associated with key "data"

I guess it must be quite straightforward mistake but I am unable to fix it.

Someone can help ?

---

<div class="post-metadata">

**Author:** ![0xTim](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/0xtim/32/27968_2.png) [@0xTim](https://forums.swift.org/u/0xTim)\
**Post date:** [February 19, 2026, 9:25am UTC](https://forums.swift.org/t/handling-file-uploads-with-multipart-form-data/84808/2 "2026-02-19T09:25:03Z")

</div>

I believe this is because the decoder expects the file to be nested, since that’s what the body will look like. So it should work with

```swift
struct MyType: Decodable {
  let file: File // note that the name here much match the key of the file here, in your case `file` because its `file=@...`, if you had `image=@...` then they property name would be `image`
}

```

Then do

```swift
let upload = try req.content.decode(MyType.self)

```

---

<div class="post-metadata">

**Author:** ![simon68](https://avatars.discourse-cdn.com/v4/letter/s/9d8465/32.png) [@simon68](https://forums.swift.org/u/simon68)\
**Post date:** [February 19, 2026, 10:01am UTC](https://forums.swift.org/t/handling-file-uploads-with-multipart-form-data/84808/3 "2026-02-19T10:01:29Z")

</div>

@0xTim thanks. It seems to work.

This is how I defined MyType:

```swift
struct MyType: Decodable {
  let file: File
    var name: String {
        return file.filename
    }
    var data: ByteBuffer {
        return file.data
    }
}

```

Otherwise in the route you have to use `file.file.filname` to refer to the filename. Here only `file.name` and `file.data` is necessary.

Now I am facing an issue with `curl`: instead of picking the file in the current directory, I don't know for what reason it is looking it in the `Library/Developer/Xcode/DerivedData/Build/Products/Debug/Public` folder !

---

<div class="post-metadata">

**Author:** ![0xTim](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/0xtim/32/27968_2.png) [@0xTim](https://forums.swift.org/u/0xTim)\
**Post date:** [February 19, 2026, 10:03am UTC](https://forums.swift.org/t/handling-file-uploads-with-multipart-form-data/84808/4 "2026-02-19T10:03:20Z")

</div>

I’m assuming the issue is where you’re saving the file? You need to set the custom working directory in Xcode:

> **[Custom Working Directory - Vapor: Getting Started → Xcode](https://docs.vapor.codes/getting-started/xcode/#custom-working-directory)**
>
> This page goes over some tips and tricks for using Xcode. If you use a different development environment, you can skip this. | Vapors documentation (web framework for Swift).

---

<div class="post-metadata">

**Author:** ![simon68](https://avatars.discourse-cdn.com/v4/letter/s/9d8465/32.png) [@simon68](https://forums.swift.org/u/simon68)\
**Post date:** [February 19, 2026, 10:11am UTC](https://forums.swift.org/t/handling-file-uploads-with-multipart-form-data/84808/5 "2026-02-19T10:11:47Z")

</div>

Ok ! I just found out it was not on `curl` as I remembered there is a warning about that in the docs.

Now it fully works ! Thanks @0xTim

---

<div class="post-metadata">

**Author:** ![simon68](https://avatars.discourse-cdn.com/v4/letter/s/9d8465/32.png) [@simon68](https://forums.swift.org/u/simon68)\
**Post date:** [February 19, 2026, 10:43am UTC](https://forums.swift.org/t/handling-file-uploads-with-multipart-form-data/84808/6 "2026-02-19T10:43:52Z")

</div>

Just one more issue.

It is working fine with the path as defined by:

```
 let path = req.application.directory.publicDirectory.appending(file.name)

```

This places the image direclty in the `Public` folder whereas I would like to have it in the `Uploads` subfolder.

However using:

> ```
> let path = req.application.directory.publicDirectory.appending("Uploads/\(file.name)")
> 
> ```

does not do anything (giving no error by the way).

---

<div class="post-metadata">

**Author:** ![evilmint](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/evilmint/32/22099_2.png) [@evilmint](https://forums.swift.org/u/evilmint)\
**Post date:** [February 19, 2026, 11:23am UTC](https://forums.swift.org/t/handling-file-uploads-with-multipart-form-data/84808/7 "2026-02-19T11:23:07Z")

</div>

This will probably give you /Public/Uploads/filename because you’re referencing `publicDirectory`.

Try printing out the variable & using

`req.application.directory.workingDirectory`

---

<div class="post-metadata">

**Author:** ![simon68](https://avatars.discourse-cdn.com/v4/letter/s/9d8465/32.png) [@simon68](https://forums.swift.org/u/simon68)\
**Post date:** [February 19, 2026, 12:03pm UTC](https://forums.swift.org/t/handling-file-uploads-with-multipart-form-data/84808/8 "2026-02-19T12:03:31Z")

</div>

@evilmint I put a breakpoint and checked value of `path` and it is exactly what I expect, ie:

`path = .../VaporProjects/myApp/Public/Uploads/appicon.png`

But the file `appicon.png` does not get uploaded.

Whereas, with :

> let path = req.application.directory.publicDirectory.appending(file.name)

so

`path = .../VaporProjects/myApp/Public/appicon.png`

and the file gets uploaded as expected in the `Public` folder.

 ![Capture d’écran 2026-02-19 à 13.04.47](https://global.discourse-cdn.com/swift/original/3X/4/b/4b4adc939938be362e2c21dca4fba95e1a0a9f96.png)

---

<div class="post-metadata">

**Author:** ![tera](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/tera/32/38201_2.png) [@tera](https://forums.swift.org/u/tera)\
**Post date:** [February 19, 2026, 1:43pm UTC](https://forums.swift.org/t/handling-file-uploads-with-multipart-form-data/84808/9 "2026-02-19T13:43:36Z")

</div>

I'd recommend you to inspect the built app: the hierarchy in Xcode might not (and most likely will not) reflect the hierarchy in the built app, I seen cases when the latter was a flattened out version.

Also, could you not use `Bundle.main.url(forResource:, withExtension:)` ?

---

<div class="post-metadata">

**Author:** ![simon68](https://avatars.discourse-cdn.com/v4/letter/s/9d8465/32.png) [@simon68](https://forums.swift.org/u/simon68)\
**Post date:** [February 23, 2026, 10:02am UTC](https://forums.swift.org/t/handling-file-uploads-with-multipart-form-data/84808/10 "2026-02-23T10:02:14Z")

</div>

@tera could you be more specific what you mean by "inspecting the built app" ?

Regarding `Bundle.main.url(forResource:, withExtension:)` I am not sure how you want to use it : I believe `fileio.writeFile()` expects a `String` path not an `url`. And in this case it is of a folder not of a resource.

Sorry, I don't catch you.

---

<div class="post-metadata">

**Author:** ![tera](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/tera/32/38201_2.png) [@tera](https://forums.swift.org/u/tera)\
**Post date:** [February 23, 2026, 10:11am UTC](https://forums.swift.org/t/handling-file-uploads-with-multipart-form-data/84808/11 "2026-02-23T10:11:27Z")

</div>

In the build log (shown in the report navigator tab) you'd see where the app is being built to, it will be a path like so:

> /Users/user/Library/Developer/Xcode/DerivedData/AppName-gjzhjglmtabhvjggthttwgfehj/Build/Products/Debug/TheApp.app

Navigate to that folder and show the package contents to reveal the actual file hierarchy inside the app package.

As for the string - you could convert URL to a path string with `url.path()`

---

<div class="post-metadata">

**Author:** ![simon68](https://avatars.discourse-cdn.com/v4/letter/s/9d8465/32.png) [@simon68](https://forums.swift.org/u/simon68)\
**Post date:** [February 23, 2026, 10:26am UTC](https://forums.swift.org/t/handling-file-uploads-with-multipart-form-data/84808/12 "2026-02-23T10:26:24Z")

</div>

@tera sorry I have no idea where to find the mentionned "report navigator tab."

Regarding the path of the file, I don't think it is the issue since I checked in Debug mode and as mentionned before the path as a String looks correct:

`path = .../VaporProjects/myApp/Public/Uploads/appicon.png`

It is just that the route does not write the file into the said path.

---

<div class="post-metadata">

**Author:** ![tera](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/tera/32/38201_2.png) [@tera](https://forums.swift.org/u/tera)\
**Post date:** [February 23, 2026, 10:37am UTC](https://forums.swift.org/t/handling-file-uploads-with-multipart-form-data/84808/13 "2026-02-23T10:37:25Z")

</div>

I meant this location in Xcode's UI:

 ![image](https://global.discourse-cdn.com/swift/original/3X/4/b/4be0d4488088aa377687ead128add1b5f93f5f53.png)

I might have misread the question though. I assumed you have a fixed set of fixed resources you are shipping with your app that you'd like to upload, and the only way to change those files is via rebuilding the app.

---

<div class="post-metadata">

**Author:** ![simon68](https://avatars.discourse-cdn.com/v4/letter/s/9d8465/32.png) [@simon68](https://forums.swift.org/u/simon68)\
**Post date:** [February 23, 2026, 10:55am UTC](https://forums.swift.org/t/handling-file-uploads-with-multipart-form-data/84808/14 "2026-02-23T10:55:15Z")

</div>

@tera

Well, good news : I tried it again this morning and now it seems to work fine. My png file was finally uploaded into the Public/Uploads folder as expected.

(The only bad news is I have no idea what was wrong las week)

Thanks for your time and sorry for the mistake.
