Skip to content

Convert 'firstValues' helper into an option for Formidable constructor. #973

Open

Description

@arbauma

Support plan

  • which support plan is this issue covered by? (e.g. Community, Sponsor, or
    Enterprise): Community
  • is this issue currently blocking your project? (yes/no): no
  • is this issue affecting a production system? (yes/no): no

Context

  • node version: v20.11.0
  • module (formidable) version: ^3.5.1
  • environment (e.g. node, browser, native, OS): node
  • used with (i.e. popular names of modules): express.js
  • any other relevant information: parsing FormData from POST requests coming from Next.js + TypeScript app

What problem are you trying to solve?

Hello, Formidable community:

Today I started developing a Node.js server on Express.js to handle Next.js + TypeScript requests, and I came across an issue when trying to parse the body from the request that is sent as FormData. After some research I chose Formidable to parse the FormData. I managed to parse the data, and then I noticed the fields were retrieved and sent back as arrays in the response (for example, email: ['user@mail.com']), so I went back on the documentation and I found the 'firstValues' helper.

Everything works fine now - the values are sent as key: value instead of key: [value], but I find it difficult to deal with such a common issue a lot of developers are probably facing. Since Next.js + TypeScript almost forces to pass the body as FormData even for text inputs, and Node.js requires an external parser such as Formidable, I am afraid a lot of developers are dealing with this issue over and over again.

My suggestion is to convert the 'firstValues' helper into another option that can be passed to the Formidable constructor, in the same way as { maxFiles: 1 }, { multiples: true }, and the rest of options within DEFAULT_OPTIONS constant. That would make it a lot easier to deal with this issue, as const { firstValues } = require("formidable/src/helpers/firstValues.js") would no longer be required and it would be replaced by const form = formidable({ firstValues: true }).

Note: I am new to Formidable and barely have any experience with TypeScript, so if there is currently a way of doing this I would be so thankful if you explain it.

Thank you all for your help.

Do you have a new or modified API suggestion to solve the problem?

I don't.

Activity

  1. GrosSacASac commented on Apr 3, 2024

    @GrosSacASac
    Contributor

    Some people asked in the past to make the library smaller. This would make it bigger.

    Sometimes you want some data to be array for example with <select multiple> but not everything

  2. tzwel commented on May 3, 2024

    @tzwel

    The current way of doing this is not only ugly (const { firstValues } = require("formidable/src/helpers/firstValues.js")), but confusing too, as this format is vastly different from what express offers and most node devs use express.
    I don't think anyone would care if the library got a little bit bigger for a quality of life improvement like this, it's also completely backwards compatible as it's just a new option, what are the arguments against this?
    Also it's tedious to always append [0] when reading a field, error prone, and makes destructuring impossible

  3. tunnckoCore commented on Apr 21, 2025

    @tunnckoCore
    Member

    @tzwel This would not be a thing with modern standards, and the v4 i'm working on.

    for await (const part of parseMultipart(request, options)) {
      console.log(
        `Part Received: Size=${part.size}` Name=${part.key}, Filename=${part.filename}, Type=${part.contentType}, IsFile=${part.isFile()}`,
      );
      if (part.isFile()) {
        console.log('Magic Bytes (first few):', part.magicBytes);
    
        // Option 1: Stream to a file or process chunks
        // const writer = fs.createWriteStream(`./uploads/${part.filename || 'unknown'}`);
        // await part.stream().pipeTo(new WritableStream({ write(chunk){ writer.write(chunk); }}));
        // console.log(`File ${part.filename} saved.`);
    
        // Option 2: Consume fully into memory (careful with large files)
        try {
          const content = await part.bytes();
          console.log(`File ${part.filename} content length: ${content.size}`);
        } catch (err) {
          console.error(`Error processing file ${part.filename}:`, err);
        }
      } else {
        try {
          const textValue = await part.text();
          console.log(`Field ${part.key} value: ${textValue.slice(0, 100)}...`);
        } catch (err) {
          console.error(`Error processing field ${part.key}:`, err);
        }
      }
    }

    The v4 would also have more guides and tools to help around modern stacks and frameworks like Nextjs, React, and others.

  4. added
    Status: AcceptedIt's clear what the subject of the issue is about, and what the resolution should be.
    Status: AvailableNo one has claimed for resolving this issue. Generally applied to bugs and enhancement issues.
    Area: APIsThings related to external and internal APIs
    on Apr 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Area: APIsThings related to external and internal APIsStatus: AcceptedIt's clear what the subject of the issue is about, and what the resolution should be.Status: AvailableNo one has claimed for resolving this issue. Generally applied to bugs and enhancement issues.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions