Creating a ToDo App with a MEVN Full Stack (Part 1)
VueJS is going to continue to rise in popularity, so it’s important to know how to integrate this Javascript framework with frequently-used technology like MongoDB, Express, and Node.
A MEVN stack is a nice little alternative to MEAN and MERN stacks which use Angular and React as their frontends, respectively.
In this two-part post, I will show how to create a simple MEVN stack in the form of a todo app. This should be enough to get you started and understand how to expand this project. This part will get you through the setup process of the frontend/backend and also get the two parts communicating.
A lot of this project has been inspired by the post written by Aneeta Sharma who first taught me to do this.
A Github repo for this project can be found here.
Creating Your Project
First, we’re going to setup the project structure. A MEVN stack, like all full stacks, will have two separate parts: a client-side for frontend framework and a server-side for backend calls.
So first navigate to your project’s root folder using cd and create client
and server
folders.
mkdir client
mkdir server
Setting Up Your Vue Frontend
First off, make sure you have Vue-Cli 3 and Vue Cli-Init installed on your system. Then, while still in the root folder, type the following command to setup your frontend.
vue init webpack client
These initializes a Vue project that uses the Webpack template. This is just the one that I like to use and have the most familiarity. If you want to see a full list of templates that you can use, head over here.
Next, you’ll be prompted to enter your project’s settings, for this, I used the following settings. Just make sure you install vue-router
as that is vital for the way I wrote this project.

Then, follow the instructions to navigate into your client
folder, install the node packages, and then finally start your project.
cd client
npm install
npm run dev
Nice! You should have the default Vue page rendering at http://localhost:8080

While this is nice, we won’t need any of this default page/styles later. Go to src/app.vue
and replace it with this much shorter piece of code that will render our pages later.
<template>
<div id="app">
<router-view/>
</div>
</template>
<script>
export default {
name: 'app',
data () {
return {
}
}
}
</script>
<style>
</style>
Now that we have the frontend setup and ready for development, let’s do the same for our backend.
Setting Up Your Backend
First, we’re going to have to navigate over to our server
folder from our client folder using the command cd ../server/
.
Then, we have to create a package.json
file that sets up npm and contains all the important metadata and script commands for your project. Run the command npm init
and just hit enter through all of the options.
If you open the package.json
file, you should see the following.
{
"name": "server",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"keywords": [],
"description": ""
}
This is great, except it doesn’t have a defined start command. The start command allows us to enter the command npm start
and have our server run.
We could add the line “start”: “node src/app.js”
, but then we would have to manually restart the server everytime we change our file. A good solution that we’ll use is to use nodemon — an npm package that detects file changes and automatically restarts your server.
First, we have to install nodemon with the command npm install --save nodemon
. This will save nodemon as a dependency for your server.
Then, we have to actually include nodemon in our start command. Your scripts
section should now have the following start command.
"scripts": {
"start": "./node_modules/nodemon/bin/nodemon.js src/app.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
Next, to actually get a working Express app, we’re going to have to install a few dependencies, namely express
, body-parser
, cors
, and morgan
. We can install these with the following command:
npm install --save express body-parser cors morgan
Now that we have installed the essential dependencies for an Express app, we have to actually create the app.js
file. So create a folder in server
called src
and create the file app.js
.

It’s finally time to work on making your server run. For starters, we are going to import the dependencies, define our express app, and make that app use the dependencies.
// import dependencies
const express = require('express')
const bodyParser = require('body-parser')
const cors = require('cors')
const morgan = require('morgan')const app = express() // create your express app// make app use dependencies
app.use(morgan('dev'))
app.use(bodyParser.json())
app.use(cors())app.listen(process.env.PORT || 8081) // client is already running on 8080
So now if we run npm start, there should be a nodemon output that says the app was started. But we can’t actually do anything with this. There are no defined routes, so even if we go to http://localhost:8081
nothing will happen. Let’s fix this.
All we have to do is define a route. I’m going to assume you have some experience with Express, so I won’t go into crazy depth about how/why this works. In app.js
// import dependencies
const express = require('express')
const bodyParser = require('body-parser')
const cors = require('cors')
const morgan = require('morgan')const app = express() // create your express app// make app use dependencies
app.use(morgan('dev'))
app.use(bodyParser.json())
app.use(cors())app.get('/todo', (req, res) => {
res.send([
'Thing 1',
'Thing 2'
])
})app.listen(process.env.PORT || 8081) // client is already running on 8080
The server should restart automatically (thanks nodemon) and if we head over to http://localhost:8081/todo
we should see our String array outputted onto the page in the format [“Thing 1”, “Thing 2”]
.
There you go — you have both your frontend and backend setup!
Routing to Your First Page
Navigate back over to the client/src
folder and create two folders: one named components
and one named router
. The components folder will store all of the components for the app, and the router folder will store all of information that allows for the app to have multiple pages.
First, we’re going to have to make our page. In your components folder, make a file called ToDo.vue
— this will be the main page that we are working with for this tutorial. Make it look like the following.
<template lang="html">
<div>
<ul>
<li>
Hello World
</li>
</ul>
</div>
</template><script>
export default {
}
</script><style lang="css"></style>
We have our first page, but we still need a way to access it from localhost. In your client folder, go to router/index.js
— this handles all of the routing for your client-side project. Put the following code in it.
import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'
import ToDo from '@/components/ToDo'Vue.use(Router)export default new Router({
routes: [
{
path: '/',
name: 'HelloWorld',
component: HelloWorld
}
{
path: '/todos',
component: ToDo
}
]
})
If we have done everything correctly, when we go to the url http://localhost:8080/#/todo
the component ToDos.vue
should be rendered — this is currently just a list of one element that prints Hello World
.
Cool — we have a multipage app! You now know basics of how to do pure frontend development in VueJS. But that’s not why you’re here. Let’s connect this to the backend.
Using Axios to Connect Client and Server
To allow our client to communicate with our server and vice-versa, we will use axios
— a package that can make HTTP requests to a node server.
First, install it using npm install --save axios
and then in your client/src
directory, create another folder called services
. In this new folder, create a file called API.js
and paste the following code.
import axios from 'axios'export default() => {
return axios.create({
baseURL: `http://localhost:8081/` // the url of our server
})
}
Then, in order to have more modular and maintainable code, let’s create another file called ToDoAPI.js
that will handle all of the server that relate to notes. In it, we will declare different functions that call the server by using the axios API that we just defined. Paste the following into ToDoAPI.js
import API from '@/services/API'export default {
getToDos () {
return API().get('todo')
}
}
Now, we have to modify our ToDo.vue
component in order to get it to properly load and display the data from the server call. First, we import ToDoAPI.js
into our Vue component so that we can call getTodos()
. Then, we call it in an async function using Javascript’s async/await syntax. Finally, this async function is called in Vue’s mounted
hook.
In order to render our data, we will use Vue’s v-for
directive to fill our list with our to-dos.
In ToDo.vue,
<template lang="html">
<div>
<ul>
<li v-for='todo in todos'>
<span>{{todo}}</span>
</li>
</ul>
</div>
</template><script>
import ToDoAPI from '@/services/ToDoAPI.js'
export default {
data () {
return {
todos: []
}
},
mounted () {
this.loadTodos()
},
methods: {
async loadTodos () {
const response = await ToDoAPI.getToDos()
this.todos = response.data
}
}
}
</script><style lang="css"></style>
Voila! We have the following output.

While it might not seem like much, there’s actually a lot happening. We have:
- A running Vue app
- A Node/Express server
- Axios communicating data between the client and server
- The client using Axios to get and render the data from the server
In the next part, we’ll get MongoDB running and also work on making everything look a lot better.