Here is the step-by-step guide to using Vue with Laravel
Step 1: Create a Laravel project
Type the following command in your terminal.
composer create-project laravel/laravel laravelvuejstutorial --prefer-dist
After installing the project, go to the folder and type the following command in your terminal.
npm install
It will install all the JavaScript dependencies regarding VueJS.
In addition, it will install laravel-mix, which you can think of as a kind of module bundle like webpack.
Now, set up a database in MySQL, and we need to configure it in Laravel. So in your project root, there is a .env file; in that file, you need to configure your username, DB name, and password.
After configuring, type the following command in your terminal.
php artisan migrate
If you will navigate to resources >> assets >> js >> components, you will see the Example.vue component is there, so basically, Laravel provides VueJS support out of the box.
However, we can use other JS frameworks like React or Angular. This component is required in the external JS file called app.js. Laravel Mix will compile this file.
I have removed the comments provided by Laravel so that the app.js file will look like this.
// app.js
require('./bootstrap');
window.Vue = require('vue');
Vue.component('example', require('./components/Example.vue'));
const app = new Vue({
el: '#app'
});
We need to install some other dependencies to run the Vue library smoothly, and also we need to use vue-router for routing our application.
npm install --save-dev vue-axios vue-loader vue-router vue-template-compiler
Step 2: Edit the default configuration.
We are going to change this file by the following code.
// app.js import Vue from 'vue'; import VueRouter from 'vue-router'; Vue.use(VueRouter); import VueAxios from 'vue-axios'; import axios from 'axios'; Vue.use(VueAxios, axios); const router = new VueRouter({ mode: 'history'}); new Vue(Vue.util.extend({ router })).$mount('#app');
We have imported vue, vue-router and vue-axios, and axios libraries for our application.
Created the router object and set the mode history to eliminate the pound (#) on every route.
Now, switch to resources >> views >> welcome.blade.php file and replace the following code with that file.
// welcome.blade.php <!doctype html> <html lang="{{ app()->getLocale() }}"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Laravel Vue CRUD Application</title> <link href="{{asset('css/app.css')}}" rel="stylesheet" type="text/css"> </head> <body> <div id="app"> </div> <script> window.Laravel = <?php echo json_encode([ 'csrfToken' => csrf_token(), ]); ?> </script> <script src="{{asset('js/app.js')}}"></script> </body> </html>
We need to create one Vue component inside resources >> assets >> js directory and call this component an App.vue.
// App.vue <template> <div class="container"> <div> <transition name="fade"> <router-view></router-view> </transition> </div> </div> </template> <style> .fade-enter-active, .fade-leave-active { transition: opacity .5s } .fade-enter, .fade-leave-active { opacity: 0 } </style> <script> export default{ } </script>
This component will work as a container of our application when the routes of our Vue application change.
According to that, different components will be rendered within the <router-view><router-view> tag.
We need to include this component in our app.js file and pass it to the Vue object while creating an instance.
// app.js import App from './App.vue'; new Vue(Vue.util.extend({ router }, App)).$mount('#app');
Go to the terminal and type the following command.
npm run watch
If you see any error, please first check if there is a dependency that needs to be installed in the first place.
Step 3: Create routes with vue-router for our application.
In the app.js file, we also include the Example.vue component because we will create routes for our application. So, first, create an array of routes in the app.js file.
// app.js const routes = [ { name: 'Example', path: '/', component: Example } ]; const router = new VueRouter({ mode: 'history', routes: routes}); new Vue(Vue.util.extend({ router }, App)).$mount('#app');
I have created an array of routes and passed them to the router object. So, your whole app.js file will look like this.
// app.js import Vue from 'vue'; import VueRouter from 'vue-router'; Vue.use(VueRouter); import VueAxios from 'vue-axios'; import axios from 'axios'; Vue.use(VueAxios, axios); import App from './App.vue'; import Example from './components/Example.vue'; const routes = [ { name: 'Example', path: '/', component: Example } ]; const router = new VueRouter({ mode: 'history', routes: routes}); new Vue(Vue.util.extend({ router }, App)).$mount('#app');
Type the following command in your terminal if everything is set up correctly.
php artisan serve
It will start the server on port 8000. So in Chrome, switch to this URL: http://localhost:8000
Step 4: Create Laravel Backend For Our Application.
The next step would be to move VueJS to Laravel and create a backend for our project. We can use Web routes or API routes, and for this project, let us stick with web routes, so we need to put all of our routes in the routes >> web.php file.
First, we are going to perform CRUD operations on items. So first, let us define the schema for it. Then we will create controllers and routes.
Go to your command line and type the following command. First, ensure you are at the root of our project folder.
php artisan make:model Item -m
It will create two files.
- Model file.
- Migration file.
Go to the migration file in the database >> migrations >> create_items_table and copy the following code.
<?php // create_items_table use Illuminate\Support\Facades\Schema; use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class CreateItemsTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('items', function (Blueprint $table) { $table->increments('id'); $table->string('name'); $table->integer('price'); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('items'); } }
Go to the terminal and type the following command.
php artisan migrate
It creates the items table in the database. Also, one model file is created in the app folder.
It is time to create one resource controller called ItemController by typing the following command.
php artisan make:controller ItemController --resource
This ItemController contains all its methods of CRUD operations. But first, we need to put the code in it.
So, I am now putting the whole file with all the operations.
<?php // ItemController.php namespace App\Http\Controllers; use Illuminate\Http\Request; use App\Item; class ItemController extends Controller { /** * Display a listing of the resource. * * @return \Illuminate\Http\Response */ public function index() { $items = Item::all(); return response()->json($items); } /** * Show the form for creating a new resource. * * @return \Illuminate\Http\Response */ public function create() { // } /** * Store a newly created resource in storage. * * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\Response */ public function store(Request $request) { $item = new Item([ 'name' => $request->get('name'), 'price' => $request->get('price') ]); $item->save(); return response()->json('Successfully added'); } /** * Display the specified resource. * * @param int $id * @return \Illuminate\Http\Response */ public function show($id) { // } /** * Show the form for editing the specified resource. * * @param int $id * @return \Illuminate\Http\Response */ public function edit($id) { $item = Item::find($id); return response()->json($item); } /** * Update the specified resource in storage. * * @param \Illuminate\Http\Request $request * @param int $id * @return \Illuminate\Http\Response */ public function update(Request $request, $id) { $item = Item::find($id); $item->name = $request->get('name'); $item->price = $request->get('price'); $item->save(); return response()->json('Successfully Updated'); } /** * Remove the specified resource from storage. * * @param int $id * @return \Illuminate\Http\Response */ public function destroy($id) { $item = Item::find($id); $item->delete(); return response()->json('Successfully Deleted'); } }
We also need to create a protected $fillable field in the Item.php file; otherwise, a ‘mass assignment exception‘ will be thrown.
<?php // Item.php namespace App; use Illuminate\Database\Eloquent\Model; class Item extends Model { protected $fillable = ['name', 'price']; }
The last step would be registering the routes in the routes >> web.php file.
<?php /* |-------------------------------------------------------------------------- | Web Routes |-------------------------------------------------------------------------- | | Here is where you can register web routes for your application. These | routes are loaded by the RouteServiceProvider within a group which | contains the "web" middleware group. Now create something great! | */ Route::get('/', function () { return view('welcome'); }); Route::resource('items', 'ItemController');
Step 5: Make three components and register with the App component.
All of our Backend is almost done. Now, if we switch to the front end in Vue.js, we need to create three components and then include them in an app.js file to register the routes, and it is good to go.
Create the following components inside resources >> assets >> js >> components.
- CreateItem.vue
- EditItem.vue
- DisplayItem.vue
// CreateItem.vue <template> <div> <h1>Create An Item</h1> <form v-on:submit.prevent="addItem"> <div class="row"> <div class="col-md-6"> <div class="form-group"> <label>Item Name:</label> <input type="text" class="form-control" v-model="item.name"> </div> </div> </div> <div class="row"> <div class="col-md-6"> <div class="form-group"> <label>Item Price:</label> <input type="text" class="form-control col-md-6" v-model="item.price" /> </div> </div> </div><br /> <div class="form-group"> <button class="btn btn-primary">Add Item</button> </div> </form> </div> </template> <script> export default { data(){ return{ item:{} } }, methods: { addItem(){ let uri = 'http://localhost:8000/items'; this.axios.post(uri, this.item).then((response) => { this.$router.push({name: 'DisplayItem'}) }) } } } </script>
Here, I have defined the template, a basic Item creation form. Then, in Javascript, I have to define the item object and post method to post the data to the Laravel backend server.
This file must be included in the app.js file to register the routes to see the form.
Okay, now create another component called DisplayItem.vue in the components folder.
// EditItem.vue <template> <div> <h1>Items</h1> <div class="row"> <div class="col-md-10"></div> <div class="col-md-2"> <router-link :to="{ name: 'CreateItem' }" class="btn btn-primary">Create Item</router-link> </div> </div><br /> <table class="table table-hover"> <thead> <tr> <td>ID</td> <td>Item Name</td> <td>Item Price</td> <td>Actions</td> </tr> </thead> <tbody> <tr v-for="item in items"> <td>{{ item.id }}</td> <td>{{ item.name }}</td> <td>{{ item.price }}</td> <td><router-link :to="{name: 'EditItem', params: { id: item.id }}" class="btn btn-primary">Edit</router-link></td> <td><button class="btn btn-danger" v-on:click="deleteItem(item.id)">Delete</button></td> </tr> </tbody> </table> </div> </template> <script> export default { data(){ return{ items: [] } }, created: function() { this.fetchItems(); }, methods: { fetchItems() { let uri = 'http://localhost:8000/items'; this.axios.get(uri).then((response) => { this.items = response.data; }); }, deleteItem(id) { let uri = `http://localhost:8000/items/${id}`; this.items.splice(id, 1); this.axios.delete(uri); } } } </script>
Here, I have written the component that displays the items in a tabular form, and also, I have defined two other buttons one is for EditItem.vue, and the other is the Delete function.
We also need to create the third and final component called EditItem.vue component.
// EditItem.vue <template> <div> <h1>Update Item</h1> <div class="row"> <div class="col-md-10"></div> <div class="col-md-2"><router-link :to="{ name: 'DisplayItem' }" class="btn btn-success">Return to Items</router-link></div> </div> <form v-on:submit.prevent="updateItem"> <div class="form-group"> <label>Item Name</label> <input type="text" class="form-control" v-model="item.name"> </div> <div class="form-group"> <label name="product_price">Item Price</label> <input type="text" class="form-control" v-model="item.price"> </div> <div class="form-group"> <button class="btn btn-primary">Update</button> </div> </form> </div> </template> <script> export default{ data(){ return{ item:{} } }, created: function(){ this.getItem(); }, methods: { getItem() { let uri = `http://localhost:8000/items/${this.$route.params.id}/edit`; this.axios.get(uri).then((response) => { this.item = response.data; }); }, updateItem() { let uri = 'http://localhost:8000/items/'+this.$route.params.id; this.axios.patch(uri, this.item).then((response) => { this.$router.push({name: 'DisplayItem'}); }); } } } </script>
Here, I have defined the Update function with its POST request.
The last step is to include all these components in the app.js file.
We can now remove the Example.vue component, as we do not need it anymore.
// app.js import Vue from 'vue'; import VueRouter from 'vue-router'; Vue.use(VueRouter); import VueAxios from 'vue-axios'; import axios from 'axios'; Vue.use(VueAxios, axios); import App from './App.vue'; import CreateItem from './components/CreateItem.vue'; import DisplayItem from './components/DisplayItem.vue'; import EditItem from './components/EditItem.vue'; const routes = [ { name: 'CreateItem', path: '/items/create', component: CreateItem }, { name: 'DisplayItem', path: '/', component: DisplayItem }, { name: 'EditItem', path: '/edit/:id', component: EditItem } ]; const router = new VueRouter({ mode: 'history', routes: routes}); new Vue(Vue.util.extend({ router }, App)).$mount('#app');
Finally, go to http://localhost:8000.
If you have any data, the home screen will look like this if you click the Create Item button.
If you click on the Edit button, this will be your page.
I have uploaded the code to Github. Below is the link to Github.
Download the Project On Github
Steps to Use Github code
- Clone the repo.
- Run this command: composer update.
- Then, run this command to install npm dependencies: npm install
- Create a .env file and config the database.
- Run this command: php artisan migrate.
- Then run this command: npm run dev.
- Next, type this command: php artisan serve. It will start the server at this URL: http://localhost:8000.
That’s it.

Krunal Lathiya is a seasoned Computer Science expert with over eight years in the tech industry. He boasts deep knowledge in Data Science and Machine Learning. Versed in Python, JavaScript, PHP, R, and Golang. Skilled in frameworks like Angular and React and platforms such as Node.js. His expertise spans both front-end and back-end development. His proficiency in the Python language stands as a testament to his versatility and commitment to the craft.
nice one, thanks
Thanks, handy all-in-one-place guide. It’d make a nice info-graphic.
Great tutorial dude, I learn a lot from you.
One suggestion though, for the delete method, you should do loop with index.
If you splice the id, it can be different value between the item index position and the id value, because the id is auto incremented. The splice method doesnt find the start parameter if the id is larger so the items data isn’t updated.
the directive:
the button:
Delete
the function:
let uri = `http://localhost/items/${id}`;
this.items.splice(index,1);
this.axios.delete(uri);
I have a problem now. As you said, web.php contains ‘resource’ route for ‘items’ and Vue is using ‘items’ too.
So when you are clicking the links and travel through javascript, everything is ok, but when you press F5 on your keyboard or try to access localhost:8000/edit/1, the web.php file comes in and says there is no route for ‘edit’!
It is single page application, you do not need to refresh the page because if you do, it will take a web.php file.
Hi Krunal,
Thanks for this tutorial, it’s really helpful to understand the concept.
However, I got an empty page though the items table contains 4 items.
Do you know what it could be behind the empty page?
A very great and super cool tutorial.
Thanks for putting this together.
I think you make the call to fetchItems ( i.e this.fetchItems(); )when any item is deleted, with this, the view is refreshed without having to refresh the page.
deleteItem(id)
{
let uri = `http://127.0.0.1:9900/items/${id}`;
this.items.splice(id, 1);
this.axios.delete(uri);
this.fetchItems();
}
Hello! thanks for this tutorial!
But i have an issue with the delete button
DELETE http://localhost:8000/items/1 500 (Internal Server Error)
Uncaught (in promise) Error: Request failed with status code 500
I think you we can also make the call to fetchItems ( i.e this.fetchItems(); ) when any item is deleted, with that the view data is refreshed without having to refresh the whole page.
deleteItem(id)
{
let uri = `http://127.0.0.1:9900/items/${id}`;
this.items.splice(id, 1);
this.axios.delete(uri);
this.fetchItems();
}
In all, a very great tutorial.
I think we can also make the call to fetchItems ( i.e this.fetchItems(); ) when any item is deleted, with that the view data is refreshed without having to refresh the whole page.
deleteItem(id)
{
let uri = `http://127.0.0.1:9900/items/${id}`;
this.items.splice(id, 1);
this.axios.delete(uri);
this.fetchItems();
}
In all, a very great tutorial.
This can be accomplished by adding/modifying the elements with an Index inside DisplayItem component:
1. Adding an Index to v-for and v-on:click
Delete
2. And in the deleteItem method
deleteItem(index, id)
{
let uri = `/items/${id}`;
this.items.splice(index, 1);
this.axios.delete(uri);
}
Please if i want to use say summernote, where will i put the libraries???
If it is downloadable via npm then it will be in the node_modules folder.
How can i pass data from one component to other component?
Use the Vuex library for state management in Vuejs.
well done
great 😉 https://github.com/fhferreira/laravel-5-vuejs
Since it is a single page app, how can I modify the route in other to allow another pages (for instance add data on users …)
Hi, how can I show related field with the other table?
it doesn’t work for me any more, example shows an empty screen without any errors
Hello There,
Thanks for great tutorial.
I have seen that and working fine in my local system @http://localhost:8000
But while i am running this project without “php artisan serve”, And with url: “http://192.168.2.212/vuedemo/laravue2/public/”, it is not displaying records.
Above URL is of my local system.
Please suggest me how to run project without “php artisan serve”. I have placed code in apache htdocs directory.
Thanks in advance.
This is the only tutorial that really make sense when you are searching how to learn vue JS in laravel
Hi,
I got an empty page, no table, no create,no edit, no delete though the table has 4 items inserted in MySQL database, no component displayed at all.
Anyone could help on the empty page?
Hi, when I delete the items, the table is not refreshing, should I add
this.axios.patch(uri, this.item).then((response) => {
this.$router.push({name: ‘DisplayItem’});
});
?
error console;
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:8000/items. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing).
Hi,
Great tutorial.
I updated the displayitems route to /items/ but it only displayed the data as json
I was also able to add the /items for edit and it worked fine
same problem
I have problem please help
error console:
Failed to load http://localhost:8000/items: No ‘Access-Control-Allow-Origin’ header is present on the requested resource. Origin ‘http://127.0.0.1:8000’ is therefore not allowed access.
Please install cors module by typing npm install cors –save on the node server
In step 2, could you specify what config file you are editing? I don’t see any mention of the filename and I’m not sure where this file should be.
Nice tutorial for creating a single page application in Laravel and Vuejs. You can also do it without using vue-router in your app. Here is an alternative method: https://www.cloudways.com/blog/laravel-vue-single-page-app/
wow nice tutorial.
but why this not work in laravel 5.6?? or i am missing some step??
the page shown like in example. but the back-end somehow does not catch the data..
Thank you for this tutorial ,, i have one problem is when my laravel&vuejs app on shared hosting the vue components doesn’t change after editing. I don’t encounter this problem on local server because i run “npm run watch” to compile assets. but on shared hosting i didn’t find a way to do that.
I recently upgraded to 5.6 from 5.2 going step by step through 5.3-5.4-5.5.
Do I need to manually copy the app.js to resources/asses/js folder?
I don’t see it there.
I have problem it display json only
great job
I got an empty page, no table, no create,no edit, no delete though the table has 4 items inserted in MySQL database, no component displayed at all.
Anyone could help on the empty page?
@Krunal, do you know how to create baseURL in vue? I want to set it so that in future i can change it at only one place
When i reload page it display 404 errror. How do i do?
how to deploy laravel + VueJs SPA application on shared hosting?
laravel 5.8.2
Vuejs 2.5.17
I’m getting path issues with the REPO version. Components is on the same level as the js/app.js that seems to expect it INSIDE the js folder. Is there something I’m missing with the path setup?
how to Using Vue.js in Laravel 5.1