Vue.js + Node.js + Express + MySQL example: Build a full-stack CRUD Application

In this tutorial, I will show you how to build full-stack (Vue.js + Node.js + Express + MySQL) example with a CRUD Application. The back-end server uses Node.js + Express for REST APIs, front-end side is a Vue client with Vue Router and axios.

More Practice: Node.js Express + Vue.js: JWT Authentication & Authorization example

Run both projects (back-end & front-end) in one place:
How to serve/combine Vue App with Express

Serverless with Firebase:
Vue Firebase Realtime Database: CRUD example
Vue Firestore: Build a CRUD App example


Vue.js + Node.js + Express + MySQL example Overview

We will build a full-stack Tutorial Application in that:

  • Tutorial has id, title, description, published status.
  • User can create, retrieve, update, delete Tutorials.
  • There is a search box for finding Tutorials by title.

Here are screenshots of the example.

– Add an object:

vue-node-express-mysql-demo-add-object

– Show all objects:

vue-node-express-mysql-demo-show-all-objects

– Click on Edit button to update an object:

vue-node-express-mysql-demo-edit-object

On this Page, you can:

  • change status to Published/Pending using Publish/UnPublished button
  • remove the object from MySQL Database using Delete button
  • update this object’s details on Database with Update button

– Search objects by field ‘title’:

vue-node-express-mysql-demo-search-objects

Full-stack CRUD App Architecture

We’re gonna build the application with following architecture:

vue-node-express-mysql-architecture

– Node.js Express exports REST APIs & interacts with MySQL Database using Sequelize ORM.
– Vue Client sends HTTP Requests and retrieves HTTP Responses using axios, consume data on the components. Vue Router is used for navigating to pages.

Node.js Express Back-end

Overview

These are APIs that Node.js Express App will export:

Methods Urls Actions
GET api/tutorials get all Tutorials
GET api/tutorials/:id get Tutorial by id
POST api/tutorials add new Tutorial
PUT api/tutorials/:id update Tutorial by id
DELETE api/tutorials/:id remove Tutorial by id
DELETE api/tutorials remove all Tutorials
GET api/tutorials?title=[kw] find all Tutorials which title contains 'kw'

Project Structure

vue-node-js-express-sequelize-mysql-example-project-structure

db.config.js exports configuring parameters for MySQL connection & Sequelize.
Express web server in server.js where we configure CORS, initialize & run Express REST APIs.
– Next, we add configuration for MySQL database in models/index.js, create Sequelize data model in models/tutorial.model.js.
– Tutorial controller in controllers.
– Routes for handling all CRUD operations (including custom finder) in tutorial.routes.js.

If you want to use raw SQL (without Sequelize), kindly visit:
Build Node.js Rest APIs with Express & MySQL

This backend works well with frontend in this tutorial.

Implementation

Create Node.js App

First, we create a folder:

$ mkdir nodejs-express-sequelize-mysql
$ cd nodejs-express-sequelize-mysql

Next, we initialize the Node.js App with a package.json file:

npm init

name: (nodejs-express-sequelize-mysql) 
version: (1.0.0) 
description: Node.js Rest Apis with Express, Sequelize & MySQL.
entry point: (index.js) server.js
test command: 
git repository: 
keywords: nodejs, express, sequelize, mysql, rest, api
author: bezkoder
license: (ISC)

Is this ok? (yes) yes

We need to install necessary modules: express, sequelize, mysql2 and body-parser.
Run the command:

npm install express sequelize mysql2 body-parser cors --save

Setup Express web server

In the root folder, let’s create a new server.js file:

const express = require("express");
const bodyParser = require("body-parser");
const cors = require("cors");

const app = express();

var corsOptions = {
  origin: "http://localhost:8081"
};

app.use(cors(corsOptions));

// parse requests of content-type - application/json
app.use(bodyParser.json());

// parse requests of content-type - application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: true }));

// simple route
app.get("/", (req, res) => {
  res.json({ message: "Welcome to bezkoder application." });
});

// set port, listen for requests
const PORT = process.env.PORT || 8080;
app.listen(PORT, () => {
  console.log(`Server is running on port ${PORT}.`);
});

What we do are:
– import express, body-parser and cors modules:

  • Express is for building the Rest apis
  • body-parser helps to parse the request and create the req.body object
  • cors provides Express middleware to enable CORS with various options.

– create an Express app, then add body-parser and cors middlewares using app.use() method. Notice that we set origin: http://localhost:8081.
– define a GET route which is simple for test.
– listen on port 8080 for incoming requests.

Now let’s run the app with command: node server.js.
Open your browser with url http://localhost:8080/, you will see:

node-js-express-sequelize-mysql-example-setup-server

Yeah, the first step is done. We’re gonna work with Sequelize in the next section.

Configure MySQL database & Sequelize

In the app folder, we create a separate config folder for configuration with db.config.js file like this:

module.exports = {
  HOST: "localhost",
  USER: "root",
  PASSWORD: "123456",
  DB: "testdb",
  dialect: "mysql",
  pool: {
    max: 5,
    min: 0,
    acquire: 30000,
    idle: 10000
  }
};

First five parameters are for MySQL connection.
pool is optional, it will be used for Sequelize connection pool configuration:

  • max: maximum number of connection in pool
  • min: minimum number of connection in pool
  • idle: maximum time, in milliseconds, that a connection can be idle before being released
  • acquire: maximum time, in milliseconds, that pool will try to get connection before throwing error

For more details, please visit API Reference for the Sequelize constructor.

Initialize Sequelize

We’re gonna initialize Sequelize in app/models folder that will contain model in the next step.

Now create app/models/index.js with the following code:

const dbConfig = require("../config/db.config.js");

const Sequelize = require("sequelize");
const sequelize = new Sequelize(dbConfig.DB, dbConfig.USER, dbConfig.PASSWORD, {
  host: dbConfig.HOST,
  dialect: dbConfig.dialect,
  operatorsAliases: false,

  pool: {
    max: dbConfig.pool.max,
    min: dbConfig.pool.min,
    acquire: dbConfig.pool.acquire,
    idle: dbConfig.pool.idle
  }
});

const db = {};

db.Sequelize = Sequelize;
db.sequelize = sequelize;

db.tutorials = require("./tutorial.model.js")(sequelize, Sequelize);

module.exports = db;

Don’t forget to call sync() method in server.js:

...
const app = express();
app.use(...);

const db = require("./app/models");
db.sequelize.sync();

...

In development, you may need to drop existing tables and re-sync database. Just use force: true as following code:


db.sequelize.sync({ force: true }).then(() => {
  console.log("Drop and re-sync db.");
});

Define the Sequelize Model

In models folder, create tutorial.model.js file like this:

module.exports = (sequelize, Sequelize) => {
  const Tutorial = sequelize.define("tutorial", {
    title: {
      type: Sequelize.STRING
    },
    description: {
      type: Sequelize.STRING
    },
    published: {
      type: Sequelize.BOOLEAN
    }
  });

  return Tutorial;
};

This Sequelize Model represents tutorials table in MySQL database. These columns will be generated automatically: id, title, description, published, createdAt, updatedAt.

After initializing Sequelize, we don’t need to write CRUD functions, Sequelize supports all of them:

  • create a new Tutorial: create(object)
  • find a Tutorial by id: findByPk(id)
  • get all Tutorials: findAll()
  • update a Tutorial by id: update(data, where: { id: id })
  • remove a Tutorial: destroy(where: { id: id })
  • remove all Tutorials: destroy(where: {})
  • find all Tutorials by title: findAll({ where: { title: ... } })

These functions will be used in our Controller.

We can improve the example by adding Comments for each Tutorial. It is the One-to-Many Relationship and I write a tutorial for this at:
Sequelize Associations: One-to-Many example – Node.js, MySQL

Or you can add Tags for each Tutorial and add Tutorials to Tag (Many-to-Many Relationship):
Sequelize Many-to-Many Association example with Node.js & MySQL

Create the Controller

Inside app/controllers folder, let’s create tutorial.controller.js with these CRUD functions:

  • create
  • findAll
  • findOne
  • update
  • delete
  • deleteAll
  • findAllPublished
const db = require("../models");
const Tutorial = db.tutorials;
const Op = db.Sequelize.Op;

// Create and Save a new Tutorial
exports.create = (req, res) => {
  
};

// Retrieve all Tutorials from the database.
exports.findAll = (req, res) => {
  
};

// Find a single Tutorial with an id
exports.findOne = (req, res) => {
  
};

// Update a Tutorial by the id in the request
exports.update = (req, res) => {
  
};

// Delete a Tutorial with the specified id in the request
exports.delete = (req, res) => {
  
};

// Delete all Tutorials from the database.
exports.deleteAll = (req, res) => {
  
};

// Find all published Tutorials
exports.findAllPublished = (req, res) => {
  
};

You can continue with step by step to implement this Node.js Express App in the post:
Node.js Rest APIs example with Express, Sequelize & MySQL

Run the Node.js Express Server

Run our Node.js application with command: node server.js.
The console shows:

Server is running on port 8080.
Executing (default): DROP TABLE IF EXISTS `tutorials`;
Executing (default): CREATE TABLE IF NOT EXISTS `tutorials` (`id` INTEGER NOT NULL auto_increment , `title` VARCHAR(255), `description` VARCHAR(255), `published` TINYINT(1), `createdAt` DATETIME NOT NULL, `updatedAt` DATETIME NOT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB;
Executing (default): SHOW INDEX FROM `tutorials`
Drop and re-sync db.

Vue.js Front-end

Overview

vue-node-express-mysql-example-vue-client-overview

– The App component is a container with router-view. It has navbar that links to routes paths.

TutorialsList component gets and displays Tutorials.
Tutorial component has form for editing Tutorial’s details based on :id.
AddTutorial component has form for submission new Tutorial.

– These Components call TutorialDataService methods which use axios to make HTTP requests and receive responses.

Technology

  • vue: 2.6.10
  • vue-router: 3.1.3
  • axios: 0.19.0

If you want to use Vue 3 instead, please visit:
Vue 3 CRUD example with Axios & Vue Router

Project Structure

vue-node-express-mysql-example-vue-client-project-structure

package.json contains 3 main modules: vue, vue-router, axios.
– There are 3 components: TutorialsList, Tutorial, AddTutorial.
router.js defines routes for each component.
http-common.js initializes axios with HTTP base Url and headers.
TutorialDataService has methods for sending HTTP requests to the Apis.
vue.config.js configures port for this Vue Client.

Implementation

Setup Vue.js Project

Open cmd at the folder you want to save Project folder, run command:
vue create vue-js-client-crud

You will see some options, choose default (babel, eslint).
After the process is done. We create new folders and files like the following tree:


public

index.html

src

components

AddTutorial.vue

Tutorial.vue

TutorialsList.vue

services

TutorialDataService.js

App.vue

main.js

package.json


Open public/index.html, add bootstrap inside <head> tag:

<!DOCTYPE html>
<html lang="en">
  <head>
    ...
    <title>vue-js-client-crud</title>
    <link type="text/css" rel="stylesheet" href="//unpkg.com/bootstrap/dist/css/bootstrap.min.css" />
  </head>
  <body>
    ...
  </body>
</html>

Add Vue Router to Vue.js 2 CRUD App

– Run the command: npm install vue-router.

– In src folder, create router.js and define Router as following code:

import Vue from "vue";
import Router from "vue-router";

Vue.use(Router);

export default new Router({
  mode: "history",
  routes: [
    {
      path: "/",
      alias: "/tutorials",
      name: "tutorials",
      component: () => import("./components/TutorialsList")
    },
    {
      path: "/tutorials/:id",
      name: "tutorial-details",
      component: () => import("./components/Tutorial")
    },
    {
      path: "/add",
      name: "add",
      component: () => import("./components/AddTutorial")
    }
  ]
});

– Open src/main.js, then import router:

import Vue from 'vue'
import App from './App.vue'
import router from './router'

Vue.config.productionTip = false

new Vue({
  router,
  render: h => h(App),
}).$mount('#app')

Add Navbar and Router View to Vue.js 2 CRUD App

Let’s open src/App.vue, this App component is the root container for our application, it will contain a navbar.

<template>
  <div id="app">
    <nav class="navbar navbar-expand navbar-dark bg-dark">
      <router-link to="/" class="navbar-brand">bezKoder</router-link>
      <div class="navbar-nav mr-auto">
        <li class="nav-item">
          <router-link to="/tutorials" class="nav-link">Tutorials</router-link>
        </li>
        <li class="nav-item">
          <router-link to="/add" class="nav-link">Add</router-link>
        </li>
      </div>
    </nav>

    <div class="container mt-3">
      <router-view />
    </div>
  </div>
</template>

<script>
export default {
  name: "app"
};
</script>

Initialize Axios for Vue.js 2 CRUD HTTP Client

Now we’re gonna install axios with command: npm install axios.
Then, under src folder, we create http-common.js file like this:

import axios from "axios";

export default axios.create({
  baseURL: "http://localhost:8080/api",
  headers: {
    "Content-type": "application/json"
  }
});

Remember to change the baseURL, it depends on REST APIs url that your Server configures.

Create Data Service

Our service will use axios from HTTP client above to send HTTP requests.

services/TutorialDataService.js

import http from "../http-common";

class TutorialDataService {
  getAll() {
    return http.get("/tutorials");
  }

  get(id) {
    return http.get(`/tutorials/${id}`);
  }

  create(data) {
    return http.post("/tutorials", data);
  }

  update(id, data) {
    return http.put(`/tutorials/${id}`, data);
  }

  delete(id) {
    return http.delete(`/tutorials/${id}`);
  }

  deleteAll() {
    return http.delete(`/tutorials`);
  }

  findByTitle(title) {
    return http.get(`/tutorials?title=${title}`);
  }
}

export default new TutorialDataService();

Create Vue Components

As I’ve said before, we have 3 components corresponding to 3 routes defined in Vue Router.

  • Add new Item
  • List of items
  • Item details

You can continue with step by step to implement this Vue App in the post:
Vue.js CRUD App with Vue Router & Axios

Or using Vuetify: Vuetify data-table example with a CRUD App

vuetify-data-table-example-crud-app-retrieve-all

Run Vue.js Client

You can run our Vue App with command: npm run serve.
If the process is successful, open Browser with Url: http://localhost:8081/ and check it.

Source Code

You can find Github source code for this tutorial at: Vue + Node.js Github

Conclusion

Now we have an overview of Vue.js + Node.js Express + MySQL example when building a full-stack CRUD App.

We also take a look at client-server architecture for REST API using Express & Sequelize ORM, as well as Vue.js project structure for building a front-end app to make HTTP requests and consume responses.

Next tutorials show you more details about how to implement the system:
– Back-end:

– Front-end:

Run both projects (back-end & front-end) in one place:
How to serve/combine Vue App with Express

If you want a Typescript version for the Vue App, it is here:
Vue Typescript CRUD Application to consume Web API example

Pagination:
Server side Pagination in Node.js with Sequelize & MySQL
Vue Pagination with Axios and API (Server Side pagination) example

Serverless with Firebase:
Vue Firebase Realtime Database: CRUD example
Vue Firestore: Build a CRUD App example

Happy learning, see you again!

41 thoughts to “Vue.js + Node.js + Express + MySQL example: Build a full-stack CRUD Application”

  1. Hey BezKoder, thanks a lot for the content. Do you have a YouTube channel where you explain and do a code along for this CRUD app? If not, it would be a great investment of you time.

  2. Hi,
    Thanks for this great work. By the way, I have a little extreme situation. Insert, Delete parts are perfectly what I look for, and in addition to this, how can I create the Tutorial table through UI too? It means, entire database items will be created through UI and data insert as well.

  3. Wow. I bookmarked this webpage several months ago, but didn’t look at it closely. I found it in a search for vue, mysql & sequelize. Then looking through your tutorial I found two more very interesting tutorials… Vue3, Axios, Express & Vue Router and Node, REST, Sequelize, MySQL. These are all very interesting to me, but what I would really like to find is using Node.js to connect to MySQL with GraphQL through Sequelize and using Vue.js on the front end. If you have a tutorial like that, then I pray you will post the link. If you don’t I hope you will make a tutorial. Your tutorials are outstanding and very impressive.

  4. Hi! Thank you for sharing.
    But you forgot to mention about routes folder where “tutorial.routes.js” should be present.
    Can you please add it.

    1. you define the location of the routes inside the server.js with this line:
      require(“./app/routes/tutorial.routes.js”)(app);

  5. Hello, thanks for the great tutorials. I worked through this one and could apply it well on my own project. I added then many-to-many relationships to the backend which also worked perfectly but now I wonder how I can fetch the newly included data from those many-to-many relationships inside my vue.js frontend.

    Is there any example where a frontend shows tutorials with several tags so I could learn from that?

  6. Thank you man! With this tutorial i programmed my own privat application. It is my first project like Fullstack!
    Radek

  7. thanks bezkoder for the code… i wanna ask something, is this support control-cache? i mean when i deploy it on web server, is the apps support cache revalidate when i change some data? thank you

  8. Way cool! I appreciate you penning this post plus the rest of the site is very good.

  9. Thank you so much!

    I got the two errors below:
    Access to XMLHttpRequest at ‘localhost:8080/api/tutorials’ from origin ‘http://localhost:8081’ has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, https.
    And
    GET localhost:8080/api/tutorials net::ERR_FAILED

    The back-end app retrieve the data as JSON when request via Postman.

  10. I found myself recommended this Vue + Node tutorial by my friend. You know such detailed about my trouble. You happen to be amazing! Thanks!

  11. First of all, thank you for this awesome post! 🙂

    I am building an application from your tutorial and now I want to list ‘Tutorials’ (found by title and author) not on the same page (this works) but on another page (another Vue component) and I don’t undestand how to do this…
    Some clue? ^^

  12. Thanks alot! Hope you keep writing more fullstack tutorials for Vue.js and Node.js like this.

  13. Thank you for the information!

    Could you tell me how to draw a chart using mysql and vue?

  14. Thanks, thanks, THANKS! One damn week searching for a way to combine vue and node, I was going to jump off the window… finally an example that works and so smooth, I love it. JUST THANK YOU!!! I did not expect it to be 2 separate projects, interesting.

  15. Thank you for this fullstack example. Please make some more tutorials about Vue.js + Node.js Express such as JWT Authentication.

      1. if it is possible to integrate with
         framework like quasar or similar
        thank you very much

Comments are closed to reduce spam. If you have any question, please send me an email.