Nuxt Project from Scratch

Nuxt.js is really easy to get started with. A simple project only needs the nuxt dependency.

Using Tooltwist Nuxt.js Starter Template

To get started quickly, the Tooltwist has created a starter template.

Download the .zip starter template or install it with vue-cli:

$ vue init tooltwist/nuxt-starter-template my-project

If vue-cli is not installed, please install it with npm install -g vue-cli

then install the dependencies:

$ cd <project-name>
$ npm install

and launch the project with:

$ npm run dev

The application is now running on http://localhost:3000.

Nuxt.js will listen for file changes inside the pages directory, so there is no need to restart the application when adding new pages.

To discover more about the directory structure of the project: Directory Structure Documentation.

Steps To Create a Project Manually

These steps were used to create the template directory in this repo.

Before Starting

Notes for Atom:

  • Use ⌘-t to jump to a file quickly.
  • Use shift-⌘-t-\ to show the currently open file in the tree on the left.

Create a default Nuxt project

$ vue init nuxt/starter <project-name>
$ cd <project-name>
$ npm install
$ npm run dev

Info: replace <project-name> by the name of the project.

Open browser at http://localhost:3000.


  • Look at pages/index.vue
    • Make a change and see it appear on the browser.
    • Notice the 3 sections to the page -
<template> contains html, <script> contains Javascript, and <style> contains CSS.
  • Look at components/AppLogo.vue
    • Contains sections, similar to index.vue, but missing <script> (he <script> and <style> sections are optional).
    • Notice that index.vue:
      • imports AppLogo.vue
      • registers it as a component
      • uses it in the HTML, as <app-logo></app-logo>

Add Pug, SCSS

npm install --save-dev pug@2.0.0-beta6 pug-loader node-sass sass-loader

Modify pages/index.vue to use Pug:

<template lang="pug">
| j1
| Nuxt.js project
a.button--green(href="", target="_blank") Documentation
a.button--grey(href="", target="_blank") GitHub

Check the page still works.


  • uses indentation to indicate nesting, which removes the need for closing tags.
  • uses CSS-like syntax for tags definitions: h1.title#heading Hello is equivalent to <h1 class=“title” id=“heading”>Hello</h1>
  • Everything is assumed a tag unless prfixed with ‘|’.
  • Indentation must correctly reflect the nesting of the html elements.

Details about ‘pug’ (previously called ‘jade’) can be found at

Add Bulma / Buefy

npm install nuxt-buefy --save

In nuxt.config.js add:

modules: [
buefy: { defaultIconPack: 'fas' }

Bulma = CSS library, like Bootstrap but newer and simpler. It makes creating responsive pages easy. See

Modify pages/index.vue:

Restart the server and see how this looks in the browser.

Buefy = Reusable components for VueJS, using Bulma

Bulma only provides CSS. Buefy provides components that extends Bulma’s CSS and may also contain Javascript code.

Add the following below the box code from above (with the same indent):

b-collapse(:open="false")"trigger") Click me!
.content Blurb
| Lorem ipsum dolor sit amet, consectetur adipiscing elit.
| Nulla accumsan, metus ultrices eleifend gravida, nulla nunceu lectus.
| Ut vulputate semper dui. Fusce erat odio, sollicitudin vel.

Note that the button defined here is NOT the same as the default buttons that came with the generated project. The button—green and button—grey came from layouts/default.vue, whereas classes button and is-primary come from Bulma.

Add Font-awesome

npm install @nuxtjs/font-awesome --save

In nuxt.config.js add:

modules: [

In pages/index.vue:

| &nbsp; Some nice text can go inside this box.

Restart the server and see how it looks.

Adjusting the Site

Update layouts/default.vue:

The page should now have a header and footer.

Add a Couple of Pages

You should now be able to navigate to these pages using the navbar at the top of the page.

Resize the screen and see how it adjusts. When the screen gets small enough it replaces the menu options with a “burger”, for mobile devices. This functionality is provided by a combination of Bulma and the toggleNavbar() method in PublicHeader.vue.

Install libraries

npm install axios debounce v-hotkey vue-drag-drop vue-froala-wysiwyg vue-split-panel vue-awesome --save

npm install vue-loginservice vue-contentservice --save

Using Tooltwist Components

Login page

Notice how the menu bar changes when the user logs in:

  • Restart the server, and log in with demo/demo.
  • The computed value ‘isLoggedIn’ changes from false to true, causing the label to switch from ‘Login’ to ‘Sign out’.
  • The computed value ‘userTitle’ gets displayed when the user is logged in.

Redirect Middleware

a) Some pages should be visible only when a user is logged in.

b) Other pages should not be shown when a user is logged in.

c) Using Nuxt middleware we can intercept the routing to a page, and forward instead to a different page if required.

d) The Server Side Rendering cannot access browser cookies, so the middleware cannot determine if the user is logged in. Instead it needs to return to a page to the browser that will immediately redirect to the required page, causing the middleware to run again, this time on the browser.

To provide this functionality, a Nuxt middleware named redirectIfServer is used.

Note that if you now try to go to privatePage without being logged in, you will be forwarded to the login page. Take a look at the output of npm run dev, and also the Javascript console of your browser and you will see debug messages explaining what the router is doing and why.
If you ever wonder why some pages cannot be accessed, this is the first place to look.

We should stop privatePage from being displayed in the user is not logged in.

Bounce Page (required for social media login)

When logging in with Facebook/Google/Github/Twitter/LinkedIn the browser redirects to their authentication server, to loginservice, and finally back to an application page with the credentials provided as a URL parameter.

> Our application (via vue-loginservice) saves these credentials in a cookie and will stay logged in until the user logs out.

This leaves a problem… after logging out, if the user returns to that page via the browser history or the back button, the URL parameters will log the user back in. To avoid this problem, we need to prevent the URL with the authentication parameters being saved in the browser history.

We do this with a page called loginservice-bounce. Loginservice will jump to this page with the credentials, and this page will save the credentials as a cookie then immediately redirect to the actually required application page, without the URL parameters for the credentials.

Account Page

Next Steps

You now have a demonstration application running, however it’s running against the demonstration user database. To create your own application:

  1. Go to and register, click on the link in the verification email, create a new application, and allocate an APIKey. Replace the default ApiKey in /protected-config/websiteConfig.js and restart your server.

  2. Create a Mailchimp/Mandrill account, and install the registration and forgot-password templates from You will also need to verify that you own the domain used to send emails to users.

  3. If you wish to allow users to log in with a social media account, you will need to register the application with Facebook/Github/etc and enter the details into A3. The help links on the config pages explains how to configure Facebook, etc.