Building your first Laravel Nova Tool
Published on by Joe Dixon
Recently, I took advantage of the Black Friday sale and, although I didn’t have a use for it, I purchased a Laravel Nova license. I had been impressed with what I had seen and was desperate to give it a try.
I decided it would be fun to port one of my open-source packages, Laravel Translation to a Nova Tool.
Related: Building a Laravel Translation Package.
If you were unaware, a Tool is Nova’s method of allowing developers to add additional custom functionality to what ships out of the box.
This article will walk you through the process I took when building it.
Nova Documentation
Not knowing where to start, I headed for the documentation. As you would expect from a Laravel product, the documentation is fantastic. There is a section dedicated to building tools as well as all the other ways of customizing Nova.
Within a few minutes, I had a grasp of what I needed to do.
Nova Scaffolding
Nova ships with a CLI command which generates the scaffolding of the tool for you, php artisan nova:tool
. When running this command, you pass in the tool’s name in Packagist vendor/name
format which it uses when generating the composer.json
file. This means it will be ready to publish as soon as development has completed.
The full scaffolding of the tool includes everything needed to get started with development including service providers, starter JavaScript, and SASS files and its class which is used to register the tool in the application.

Nova Service Provider
A tool has its service provider where it can be bootstrapped. This acts much like a Laravel service provider. It extends Illuminate\Support\ServiceProvider
used in a standard Laravel application. This means all the methods like loading routes, views, migrations, etc. are available to you.
Unlike a standard Laravel service provider, all the necessary wiring up of views and routes is provided out of the box.
// Views$this->loadViewsFrom(__DIR__.'/../resources/views', 'nova-translation'); // RoutesRoute::middleware(['nova', Authorize::class]) ->prefix('nova-vendor/nova-translation') ->group(__DIR__.'/../routes/api.php');
As you can see, there is some Laravel Nova middleware automatically applied to the routes. The nova
middleware group which applies any middleware defined in the nova.php
configuration file and the Authorize::class
which applies any custom authorization set in the tool class. More on this later.
The routes are also registered under your vendor prefix, so they don’t conflict with any other routes.
Finally, your routes are loaded from the routes/api.php
file that is automatically generated with the tool.
Nova Tool Class
As previously mentioned, the tool class is created automatically for you. It is named using the studly-cased version of the name you provided when running php artisan nova:tool vendor/name
.
You don’t have to do anything in here, but it is possible to modify the way you render your navigation or which assets should be loaded.
For my package, I didn’t need to make any changes to this file.
Nova Navigation
Nova makes it incredibly easy to add a link to your tool in the main sidebar of the application. Once again, this is generated automatically by providing a navigation.blade.php
file containing a default navigation link and loading it from the tool class.
public function renderNavigation(){ return view('nova-translation::navigation');}
You are free to edit this file to suit your needs. Typically, this will involve updating the SVG icon rendered in the navigation. Conveniently, Nova ships with a set of icons you are free to use.
Laravel Nova Frontend
The Nova frontend is a Vue.js application. A new tool is initialized with a tool.js
file where you can use Vue’s router to define any routes needed. From there, you are free to build the application as you wish. As you would expect, the route to the index of your app is defined for you, but you are free to update it if required.
Nova.booting((Vue, router) => { router.addRoutes([ { name: 'nova-translation', path: '/nova-translation', component: require('./views/LanguagesIndex'), }, ... ])})
Tools are compiled using Laravel Mix, and a configuration file is included as part of the scaffolding. This allows you to run development and production builds, and even trigger a rebuild when files change using commands you are likely familiar with such as npm run watch
.
One of the things I liked when developing the frontend was the ability to utilize all the Vue components from the core of Nova.
It’s incredibly useful to be able to pull in things like loading views which automatically handle the loading state of your component or dropdown components for building out the user interface.
<template> <loading-view :loading="initialLoading"> // ships with Nova <loading-card :loading="loading" class="card"> // ships with Nova // show something custom in here when loading state changes </loading-card> </loading-view></template> <script>export default { data() { return { initialLoading: true, loading: false, languages: {} } }, methods: { listLanguages() { Nova.request().get('/nova-vendor/nova-translation/languages') .then((response) => { this.languages = response.data; this.initialLoading = false; this.loading = false; }) } }, created() { this.listLanguages() },}</script>
As you can see above, I use the LoadingView
and LoadingCard
components that ship with Nova. I then pass the loading state of my component as a prop and the loading state transition is handled for me. The result is the loading animation being rendered while my data is prepared.

Registering a Nova Tool
With the tool built, the last stage of the process is to let Nova know about its existence by registering it to the application. This is done by adding the tool class to the registerTools
method of the NovaServiceProvider
.
protected function registerTools(){ Nova::tools([ new Dashboard, new ResourceManager, new NovaTranslation, ]);}
Laravel Community
Taking a step away from the technical implementation, I wanted to highlight something that happened during the development of this tool.
During the build, I wanted to implement the blue loading bar at the top of the page when carrying out an ajax-powered search. If you have used Nova before, it’s the same loader that appears when you search through any of your resources.
I was tired and burning the midnight oil trying to get it finished and could not figure it out. I decided to contact David on Twitter for some advice. Ten minutes later, I had a reply with exactly what I needed to know.
When you search the query string is updated and that bar shows up when navigating to new URLs.
— HEMPHILL (@davidhemphill) November 29, 2018
A big thank you to David for helping me through this issue, but also to the broader Laravel community. This is not, and certainly won’t be the last time I have been offered assistance from members of the community when in need.
Conclusion
The developer experience for Nova was fantastic. From not knowing where to start to have my package ported over only took a couple of evenings which is a testament to, not only the documentation but also the planning and execution of Nova itself. As with all things in the Laravel ecosystem, it’s been built with extreme care and attention to detail, making the onboarding experience for developers quick and painless. I, for one, can’t wait to start the next one!
If you want to look at the tool I built, check it out on Nova Packages and as always, if you have any questions, you can find me on Twitter.