skip to content

What changes when an HTML <form> uses method="get" instead of method="post", and how do you choose between them?

level: middleimportance: must knowfreq 70%

answer

  1. query string versus request body
  2. the URL is the result, or it is not
  3. GET replaces the action's existing query
  4. only a body can carry a file
  5. reads repeat safely, writes should not

basics

~20 s

With method="get" the browser puts the form's entries in the URL query string, so the result is bookmarkable and reloadable; with method="post" it puts them in the request body, which supports file uploads and keeps values out of the URL and history.

solid answer

~40 s

Both methods build the same entry list; they differ in where it goes. `method="get"` serializes it into the action URL's query string — and *replaces* any query already in `action`, which is why a hardcoded `?page=2` in the action disappears and has to be a hidden input instead. That makes the result linkable, bookmarkable and safe to reload, so it is the right choice for search and filter forms. `method="post"` sends the entries as a request body, which is what lets you use `enctype="multipart/form-data"` for file uploads and keeps values out of the URL bar, browser history and referrers. It is the choice for anything that changes state, since reloading a GET result re-runs it invisibly while reloading a POST result prompts the user. `enctype` is ignored for GET entirely.

go deeper

for a junior

Know that GET puts the fields in the URL after a question mark and POST puts them in the request body, and that logins and uploads use POST.

for a middle

Explain that both build the same entry list, that GET overwrites the action URL's query, that enctype only applies to POST, and why file uploads need a body.

for a senior

Argue the choice from effects: reads are repeatable and deserve an addressable URL; writes get POST plus post/redirect/get so reloads never resubmit. Call out URL leakage into history, logs and referrers.

for a principal

Set the house rule so endpoints and forms agree on which submissions are safe to repeat, and make sure link prefetching, retries and caching layers cannot silently re-trigger a state change.

## Same entries, different destination Whichever method you pick, the browser first constructs the same entry list of name/value pairs from the named, enabled controls. `method` decides only how that list travels. **GET.** The list is percent-encoded as `name=value` pairs joined by `&` and becomes the query component of the action URL. The browser then navigates there. ```html <form action="/search" method="get"> <input type="search" name="q"> <button>Search</button> </form> ``` Submitting with `q=forms` requests `/search?q=forms`. **POST.** The list is placed in the request body, encoded according to `enctype`, and the URL stays exactly as written in `action`. ## The gotcha: GET discards the action's existing query This one bites nearly everyone once. Given `action="/search?page=2"`, a GET submission does **not** append to the existing query — it replaces the whole query with the serialized entry list, so the request is `/search?q=forms` and `page=2` is gone. The fix is to make the parameter part of the form: ```html <form action="/search" method="get"> <input type="hidden" name="page" value="2"> <input type="search" name="q"> </form> ``` POST does not have this problem: the action URL, query and all, is used verbatim, and the entries ride in the body. ## What each one buys you GET's real property is that **the resulting page is fully described by its URL**. That makes it shareable, bookmarkable, addressable by a link, and cacheable; the back and forward buttons move through result pages sensibly, and a reload just re-runs a read. This is exactly what you want for search, filtering, sorting and pagination — the form is a way of composing a URL. POST's properties are the mirror image. Values are not in the URL, so they do not land in bookmarks, browser history, or the referrer sent to third-party resources on the next page. There is no practical length ceiling from URL limits. And crucially, only POST can carry a body, which is what makes `enctype="multipart/form-data"` — and therefore file uploads — possible. Reloading the resulting page makes the browser warn before resubmitting, a friction that is appropriate when the submission changed something. Setting `enctype` on a GET form does nothing at all; there is no body to encode. ## The decision rule Use GET when the submission *reads* — it should be safe to repeat, and repeating it must have no side effects. Use POST when the submission *writes*: creating, updating, deleting, sending money, logging in. The rule is about the effect, not about sensitivity: putting a password in a GET form is bad because it lands in history and logs, but even a harmless write belongs in POST, because things that repeat safely and things that do not should not look the same to the browser, to a link prefetcher, or to a user who hits reload. A practical corollary for state-changing forms is the post/redirect/get pattern: handle the POST, then redirect to a GET-addressable result page, so the user's reload re-runs a read instead of the write. ## Related markup you should know - A submit button can override the form for its own activation with `formmethod`, so one button in a GET search form can POST to a different endpoint. - `method` and `action` are readable from script as `form.method` and `form.action`, which is how you reuse the markup's intent when you take submission over with `fetch`. - Whatever you choose, the method is a hint about intent, not a security boundary. A POST body is exactly as forgeable as a query string; both are user input and both must be validated server-side. ## Common misreadings "POST is encrypted" is false — only HTTPS encrypts anything, and it encrypts the URL of a GET request too. "GET has a 255-character limit" is folklore; there is no limit in the markup, only practical ceilings imposed by browsers, servers and proxies, which is a reason to prefer POST for large payloads but not a fixed number to quote.

  • Why do search and filter forms almost always use GET even when the query is long?
    Because the point of a search result is that it has an address. With GET the whole query lives in the URL, so users can bookmark it, share it, link to it from a report, and use back/forward across result pages; a reload simply re-runs the read. POST would make identical results unreachable by URL and turn every reload into a resubmission prompt.
  • A form has action="/reports?year=2026" and method="get", and the year parameter keeps disappearing. Why?
    GET replaces the action URL's entire query with the serialized entry list, so `year=2026` is discarded on submit. Move it into the form as `<input type="hidden" name="year" value="2026">`, and it will be serialized alongside the other entries. POST would have kept the action's query intact, since its entries travel in the body.
  • Is POST a security measure compared with GET?
    No. A POST body is user-controlled and just as easy to forge as a query string, so both need server-side validation and authorization. What POST genuinely avoids is *leakage by URL*: values do not appear in the address bar, browser history, bookmarks, server access logs or referrers. That is a privacy and hygiene win, not an authenticity guarantee.

saying these in an interview costs you the question

  • Says POST is encrypted while GET is plain text
  • Quotes a fixed character limit for GET form data
  • Expects GET to append to a query already in the action
  • Uses GET for actions that change server state
  • Thinks setting enctype changes anything on a GET form

context