Table of contents

POST Request in Nuxt 3

Post requests in Nuxt 3 aren't as obvious as you might imaging. In this post I'll show you everything you need to get up and running and avoid common mistakes!

POST Requests in Nuxt 3

In this post we are going to look at POST requests in Nuxt 3. This is something that should be really simple to do, and to be honest with you it is. However if you are a moron like me you might find yourself spending two days trying to figure it out. In this post I’ll go over everything you need to get POST requests working in Nuxt 3. I’ll over go over some of the issues I encountered when trying to figure out how to make it work, and the solutions. I’ll even go over fixing CORS issues! You’re welcome. Feel free to follow along with the video, or checkout the detailed instructions below.

Step 1: Create a new Nuxt 3 Project (optional)

If you are already setup with an existing Nuxt 3 project you can skip this step. If you haven’t already got a Nuxt 3 project set up, go ahead and do this. Instructions on how to do this can be found in the nuxt documentation but its just a case of running the following commands:

npx nuxi init 

Once you have run this command, navigate into your newly created project, install it, and start the development server. Like this:

npm install
npm run dev -- -o

You now have your Nuxt 3 project setup and ready to go!

Step 2: Create a form in Nuxt 3 to Submit a POST Request from

In our Nuxt 3 project we are going to create a form. This form is where we are going to submit our POST request from.

Our Form

Within our template tags, we can create our form. Create your form with whatever inputs you require. For our form we will have the inputs: ‘name’, ’email’ and ‘message’. We will bind these to a formData object using v-model. Checkout the code below and make sure you have something similar. Please note, I have removed some of the markup that you see in the video to make it easier to see what’s going on, and also because I am using tailwindcss classes in the video which you don’t need.

        <form @submit.prevent="submitForm">
                <label for="name">Name</label>
                <input type="text" v-model="" id="name" placeholder="eg. John Smith" />

                <label for="email">Email</label>
                <input type="email" v-model="" id="email" placeholder="[email protected]" />

                <label for="message">Message</label>
                <textarea id="message" v-model="formData.message" placeholder="Your message..." />

                <button type="submit">Submit Form</button>

Our Script

Now we have the form, we need to bind the form inputs to a formData object which we will create. This is done using v-model on each input, with the name corresponding to the value on the formData object. Create the following script below your template:

<script setup>
import { ref } from 'vue'

const formData = ref({
    name: '',
    email: '',
    message: '',

const submitForm = async () => {
    const { data: responseData } = await useFetch('http://localhost:8888/tutorial-form-handler/index.php', {
        method: 'post',
        body: { 
          message: formData.value.message, 

What is happening in this script?

In this script, we declare a formData object with the values: name, email and message. These values correspond to the inputs created in our form, and are bound using v-model (see the inputs in the form). We have also created a’submitForm’ function. This is the function that gets executed when we click our submit button in our form. Let’s have a look at this function in more detail.

Post request with useFetch in Nuxt 3

Looking at our submitForm function, you will see that it itself makes use of “useFetch”. Now if you are familiar with making http requests with axios or another library this structure should look familiar. We have the url where the POST request is going to be submitted to, we have the method, which is set to post, and we have the body which is set to the values from our formData object. You will notice that there are no headers defined, this is because they are NOT required.

nuxt useFetch post meme

Creating our PHP file to handle the POST request

We now need to create our PHP file to handle the POST request that we receive from our Nuxt 3 application. We also need to be able to serve this PHP file so that it can actually handle the POST request. I am going to be using MAMP to do this. So I am going to create a new directory within my “Applications/MAMP/htdocs” directory and I am going to call this “tutorial-form-handler”, you are free to name this whatever you like, but remember that you need to reference it with the correct name in your useFetch function. Within this new directory I am going to create an index.php file which will be responsible for handling the POST request from our Nuxt 3 application. Copy and paste the following code into your newly created index.php file:


// For development only (CORS issues)
header('Access-Control-Allow-Origin: *'); // For development only
header('Access-Control-Allow-Methods: GET, POST'); // For development only
header("Access-Control-Allow-Headers: origin, content-type, accept, x-requested-with"); // For development only

header('Content-Type: application/json; charset=utf-8');

$post_body = file_get_contents('php://input');
$post_body_decoded = json_decode($post_body, true);

$response_data = [
    'success' => true,
    'what_we_posted' => $post_body_decoded,

echo json_encode($response_data);

Let’s have a look at what is happening in this code.

CORS issues with Post requests in Nuxt 3

CORS can be a nightmare, and while it exists to protect us it can be a huge cause of frustration. Luckily it is really east to solve. It’s worth noting that what I’m about to tell you can be used locally whilst in development, but when you want to go live with your project on a live server, you will need to delete it. Don’t worry though, it will work on the live server.

Headers to solve CORS issue

So if you have a look at the top of your newly created index.php file, you will see 3 headers: header(‘Access-Control-Allow-Origin: *’), header(‘Access-Control-Allow-Methods: GET, POST’) and header(“Access-Control-Allow-Headers: origin, content-type, accept, x-requested-with”). And that is literally all you need to include to solve your CORS issue. The headers mean that your browser won’t freak out about the POST request coming from an origin that is different from where you are posting it to. This is because your origin is http://localhost:3000 and the origin is http://localhost:8888, and your browser does not like this as it could be potentially dangerous.

Header to return data back in correct format

Along with the headers that deal with CORS, you will see another header: header(‘Content-Type: application/json; charset=utf-8’); This is to send our response back to our Nuxt 3 application as the application/json content type. This will allow us to handle the response and access the parts of the response rather than dealing with one long string of data.

Get your POST request data with file_get_contents(‘php://input’)

If you are anything like me, this is what has been causing you the biggest issue. For some reason this is not documented clearly ANYWHERE on the entire internet (don’t quote me on that). Basically, in order to actually do anything with the POST body data we need to create a variable equal to file_get_contents(‘php://input’), like this:

$post_body = file_get_contents('php://input');

Once we have created this variable containing our POST data, we need to decode it using json_decode, like this:

$post_body_decoded = json_decode($post_body, true);

Now we have our decoded post body, we can access each post body param easily. For example if we want to access just the email param we would do this like so:

$email_address = $post_body_decoded['email'];

At this point you would actually do something with the data, probably start with validation then send an email or process the data however you want. We aren’t going to do anything with the data in this example except return it to our Nuxt 3 application.

The Response

Return a response to our Nuxt 3 application

We are now ready to return a response to our Nuxt 3 application. To do this, simply create an array ($response_data in our case), create some key value pairs, encode the array and echo it:

$response_data = [
    'success' => true,
    'what_we_posted' => $post_body_decoded,

echo json_encode($response_data);

Handle the response in Nuxt 3

The response will now be returned to our Nuxt 3 application. Here we can do whatever we wish to with the response, but in our example we will log the response to the console so that we can see that it is actually working.


With a bit of luck you will see the data returned from your PHP file!

Gotchas to look out for

There are a few ‘gotchas’ that are worth looking out for.

PHP version

Your PHP version may cause some issues. Depending on your PHP version you may encounter certain warnings OR not encounter them. For example, if you are using PHP version 8.2.0 and you use this header in your POST request from Nuxt 3:

headers: {
            "Content-Type": "multipart/form-data",

Then you will get a warning in your response saying “<b>Warning</b>: Missing boundary in multipart/form-data POST data in <b>Unknown</b> on line <b>0</b><br />”. You will also see this warning if you are using an older version of PHP and do not include the Content-Type header. This is one of those weird things that isn’t documented particularly well.


I have videos too!

If you found this post helpful, please consider subscribing to the @codingoblin YouTube channel 😀

Want updates when I release something interesting?

Sign up for my newsletter to stay up to date.