diff --git a/README.md b/README.md
index acedeb09..9b0e51d8 100644
--- a/README.md
+++ b/README.md
@@ -158,11 +158,9 @@ in case of a `'unhandledRejection'`.
 `fastify-cli` can also help with generating some project scaffolding to
 kickstart the development of your next Fastify application. To use it:
 
-1. `mkdir yourapp`
+1. `fastify generate <yourapp>`
 2. `cd yourapp`
-3. `npm init`
-4. `fastify generate`
-5. `npm install`
+3. `npm install`
 
 The sample code offers you four npm tasks:
 
diff --git a/app_template/.gitignore b/app_template/.gitignore
new file mode 100644
index 00000000..36ddc84e
--- /dev/null
+++ b/app_template/.gitignore
@@ -0,0 +1,66 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+
+# Runtime data
+pids
+*.pid
+*.seed
+
+# Directory for instrumented libs generated by jscoverage/JSCover
+lib-cov
+
+# Coverage directory used by tools like istanbul
+coverage
+
+# nyc test coverage
+.nyc_output
+
+# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
+.grunt
+
+# node-waf configuration
+.lock-wscript
+
+# Compiled binary addons (http://nodejs.org/api/addons.html)
+build/Release
+
+# Dependency directories
+node_modules
+jspm_packages
+
+# Optional npm cache directory
+.npm
+
+# Optional REPL history
+.node_repl_history
+
+# 0x
+profile-*
+
+# mac files
+.DS_Store
+
+# vim swap files
+*.swp
+
+# webstorm
+.idea
+
+# vscode
+.vscode
+*code-workspace
+
+# clinic
+profile*
+*clinic*
+*flamegraph*
+
+# lock files
+yarn.lock
+package-lock.json
+
+# generated code
+examples/typescript-server.js
+test/types/index.js
diff --git a/generate.js b/generate.js
index 024ec63e..728ecef3 100755
--- a/generate.js
+++ b/generate.js
@@ -2,71 +2,75 @@
 
 const {
   readFile,
-  writeFile
+  writeFile,
+  existsSync
 } = require('fs')
 const chalk = require('chalk')
 const path = require('path')
 const generify = require('generify')
 const argv = require('yargs-parser')
-const templatedir = path.join(__dirname, 'app_template')
 const cliPkg = require('./package')
+const { execSync } = require('child_process')
 
 function generate (dir, log, cb) {
   if (!cb) {
     cb = log
     log = () => {}
   }
-  const pkgFile = path.join(dir, 'package.json')
-  log('info', `reading package.json in ${dir}`)
-  readFile(pkgFile, (err, data) => {
+
+  generify(path.join(__dirname, 'app_template'), dir, {}, function (file) {
+    log('debug', `generated ${file}`)
+  }, function (err) {
     if (err) {
       return cb(err)
     }
 
-    var pkg
-    try {
-      pkg = JSON.parse(data)
-    } catch (err) {
-      return cb(err)
-    }
+    process.chdir(dir)
+    execSync('npm init -y')
 
-    pkg.scripts = Object.assign(pkg.scripts || {}, {
-      'test': 'tap test/*.test.js test/*/*.test.js test/*/*/*.test.js',
-      'start': 'fastify start -l info app.js',
-      'dev': 'fastify start -l info -P app.js'
-    })
+    log('info', `reading package.json in ${dir}`)
+    readFile('package.json', (err, data) => {
+      if (err) {
+        return cb(err)
+      }
 
-    pkg.dependencies = Object.assign(pkg.dependencies || {}, {
-      'fastify': cliPkg.dependencies.fastify,
-      'fastify-plugin': cliPkg.devDependencies['fastify-plugin'] || cliPkg.dependencies['fastify-plugin'],
-      'fastify-autoload': cliPkg.devDependencies['fastify-autoload'],
-      'fastify-cli': '^' + cliPkg.version
-    })
+      var pkg
+      try {
+        pkg = JSON.parse(data)
+      } catch (err) {
+        return cb(err)
+      }
 
-    pkg.devDependencies = Object.assign(pkg.devDependencies || {}, {
-      'tap': cliPkg.devDependencies['tap']
-    })
+      pkg.main = 'app.js'
 
-    log('debug', `edited package.json, saving`)
+      pkg.scripts = Object.assign(pkg.scripts || {}, {
+        'test': 'tap test/*.test.js test/*/*.test.js test/*/*/*.test.js',
+        'start': 'fastify start -l info app.js',
+        'dev': 'fastify start -l info -P app.js'
+      })
 
-    writeFile(pkgFile, JSON.stringify(pkg, null, 2), (err) => {
-      if (err) {
-        return cb(err)
-      }
+      pkg.dependencies = Object.assign(pkg.dependencies || {}, {
+        'fastify': cliPkg.dependencies.fastify,
+        'fastify-plugin': cliPkg.devDependencies['fastify-plugin'] || cliPkg.dependencies['fastify-plugin'],
+        'fastify-autoload': cliPkg.devDependencies['fastify-autoload'],
+        'fastify-cli': '^' + cliPkg.version
+      })
 
-      log('debug', `saved package.json`)
-      log('info', `copying sample project`)
+      pkg.devDependencies = Object.assign(pkg.devDependencies || {}, {
+        'tap': cliPkg.devDependencies['tap']
+      })
 
-      generify(templatedir, dir, {}, function (file) {
-        log('debug', `generated ${file}`)
-      }, function (err) {
+      log('debug', `edited package.json, saving`)
+      writeFile('package.json', JSON.stringify(pkg, null, 2), (err) => {
         if (err) {
           return cb(err)
         }
 
+        log('debug', `saved package.json`)
         log('info', `project ${pkg.name} generated successfully`)
         log('debug', `run '${chalk.bold('npm install')}' to install the dependencies`)
         log('debug', `run '${chalk.bold('npm start')}' to start the application`)
+        log('debug', `run '${chalk.bold('npm run dev')}' to start the application with pino-colada pretty logging (not suitable for production)`)
         log('debug', `run '${chalk.bold('npm test')}' to execute the unit tests`)
         cb()
       })
@@ -88,7 +92,20 @@ const colors = [
 
 function cli (args) {
   const opts = argv(args)
-  generate(opts._[0] || process.cwd(), log, function (err) {
+
+  if (opts._[0] && existsSync(opts._[0])) {
+    log('error', 'directory ' + opts._[0] + ' already exists')
+    process.exit(1)
+  }
+
+  const dir = opts._[0] || process.cwd()
+
+  if (existsSync(path.join(dir, 'package.json'))) {
+    log('error', 'a package.json file already exists in target directory')
+    process.exit(1)
+  }
+
+  generate(dir, log, function (err) {
     if (err) {
       log('error', err.message)
       process.exit(1)
diff --git a/test/generate.js b/test/generate.js
index 054aaf97..41025c9e 100644
--- a/test/generate.js
+++ b/test/generate.js
@@ -6,7 +6,6 @@ process.env.TAP_BAIL = true
 
 const t = require('tap')
 const {
-  writeFile,
   readFile
 } = require('fs')
 const path = require('path')
@@ -17,6 +16,7 @@ const { generate } = require('../generate')
 const workdir = path.join(__dirname, 'workdir')
 const templatedir = path.join(__dirname, '..', 'app_template')
 const cliPkg = require('../package')
+const { exec } = require('child_process')
 const expected = {}
 
 ;(function (cb) {
@@ -59,63 +59,45 @@ function define (t) {
     })
   })
 
-  test('errors if package.json is not there', (t) => {
+  test('errors if directory exists', (t) => {
     t.plan(2)
-
-    generate(workdir, function (err) {
-      t.ok(err)
-      t.equal(err.code, 'ENOENT')
+    exec('node generate.js ./test/workdir', (err, stdout) => {
+      t.is('directory ./test/workdir already exists', stdout.toString().trim())
+      t.is(1, err.code)
     })
   })
 
-  test('finish succesfully if package.json is there - npm', (t) => {
-    t.plan(12 + Object.keys(expected).length * 2)
-
-    const pkgFile = path.join(workdir, 'package.json')
-    const pkgContent = JSON.stringify({
-      name: 'an-npm-app',
-      version: '0.0.1',
-      description: 'whaat',
-      main: 'index.js',
-      scripts: {}
-    }, null, 2)
-
-    writeFile(pkgFile, pkgContent, function (err) {
-      t.error(err)
-      generate(workdir, function (err) {
-        t.error(err)
-        verifyPkg(t, pkgFile, pkgContent)
-        verifyCopy(t, pkgFile)
-      })
+  test('errors if pkgfile exists', (t) => {
+    t.plan(2)
+    exec('node generate.js', (err, stdout) => {
+      t.is('a package.json file already exists in target directory', stdout.toString().trim())
+      t.is(1, err.code)
     })
   })
 
-  test('finish succesfully if package.json is there - yarn', (t) => {
-    t.plan(12 + Object.keys(expected).length * 2)
+  test('should finish succesfully', (t) => {
+    t.plan(15 + Object.keys(expected).length * 2)
 
-    const pkgFile = path.join(workdir, 'package.json')
-    const pkgContent = JSON.stringify({
-      name: 'an-yarn-app',
-      version: '0.0.1',
-      description: 'whaat',
-      main: 'index.js'
-    }, null, 2)
-    writeFile(pkgFile, pkgContent, function (err) {
+    generate(workdir, function (err) {
       t.error(err)
-
-      generate(workdir, function (err) {
-        t.error(err)
-        verifyPkg(t, pkgFile, pkgContent)
-        verifyCopy(t, pkgFile)
-      })
+      verifyPkg(t)
+      verifyCopy(t)
     })
   })
 
-  function verifyPkg (t, pkgFile, pkgContent) {
+  function verifyPkg (t) {
+    const pkgFile = path.join(workdir, 'package.json')
+
     readFile(pkgFile, function (err, data) {
       t.error(err)
-      t.equal(data.toString().split('"main"')[0], pkgContent.split('"main"')[0])
       const pkg = JSON.parse(data)
+      t.equal(pkg.name, 'workdir')
+      t.equal(pkg.version, '1.0.0')
+      t.equal(pkg.description, '')
+      t.equal(pkg.author, '')
+      // by default this will be ISC but since we have a MIT licensed pkg file in upper dir, npm will set the license to MIT in this case
+      // so for local tests we need to accept MIT as well
+      t.ok(pkg.license === 'ISC' || pkg.license === 'MIT')
       t.equal(pkg.scripts.test, 'tap test/*.test.js test/*/*.test.js test/*/*/*.test.js')
       t.equal(pkg.scripts.start, 'fastify start -l info app.js')
       t.equal(pkg.scripts.dev, 'fastify start -l info -P app.js')
@@ -127,7 +109,9 @@ function define (t) {
     })
   }
 
-  function verifyCopy (t, pkgFile) {
+  function verifyCopy (t) {
+    const pkgFile = path.join(workdir, 'package.json')
+
     walker(workdir)
       .on('file', function (file) {
         if (file === pkgFile) {