Skip to content
On this page

Developer Blog

Getting Started with the nuxt-directus Module

Published August 15th, 2023

Written By
Conner Bachmann
Conner Bachmann
Guest Author
With Thanks To
Kevin Lewis

In this blog post, you will explore the nuxt-directus module and cover the setup process, and how to manage items, files, and authentication. As a member of both the Nuxt and Directus communities, I am the author and maintainer of this module and work to keep it up to date with new Directus' new features. You can read the documentation of nuxt-directus at nuxt-directus.site.

Before you start

You will need:

Setup Nuxt

Open the terminal, intialize a new Nuxt project, and install the nuxt-directus module:

npx nuxt init my-website
cd my-website 
npm install
npm install nuxt-directus –save-dev
npx nuxt init my-website
cd my-website 
npm install
npm install nuxt-directus –save-dev

You have now installed the module and created a new Nuxt project.

Create a Directus Collection

Before you can work with items on the frontend, you first have to create a collection in your Directus project.

Create a Product collection which contains a title (string) and a price (string) as mandatory fields, leaving the id with default settings, which is a number.

A “Product” Data Model in Directus, the data model contains id, title, price, user_created

Configuring nuxt-directus

In your code editor open the folder my-website. The nuxt.config.ts file contains your Nuxt configuration - include and add the nuxt-directus configuration:

js
export default defineNuxtConfig({
  devtools: { enabled: true },
  modules: ["nuxt-directus"], 
  directus: { 
     url: "https://your-directus-project/" 
  } 
})
export default defineNuxtConfig({
  devtools: { enabled: true },
  modules: ["nuxt-directus"], 
  directus: { 
     url: "https://your-directus-project/" 
  } 
})

The directus config key is where you configure the nuxt-directus module. Add your URL so that the module knows which Directus instance it has to connect to.

Items CRUD With nuxt-directus

The nuxt-directus module offers two practical composables to help you work with Directus collections and items - useDirectusCollections to manage the collections itself, and useDirectusItems for managing the items within a collection.

Fetching Items

In the app.vue file of your Nuxt project remove <NuxtWelcome /> and replace it with <NuxtPage />. This tells Nuxt to use file-based routing. After that create a pages/ directory.

To fetch items, import the getItems function from the useDirectusItems composable. Inside of the pages/ directory, create and open an items.vue file:

vue
<template>
	{{ products }}
</template>

<script setup lang="ts">
const { getItems } = useDirectusItems();

interface Product {
	id: number;
	title: string;
    price: string;
}

const products = await getItems<Product>({
    collection: "product"
});
</script>
<template>
	{{ products }}
</template>

<script setup lang="ts">
const { getItems } = useDirectusItems();

interface Product {
	id: number;
	title: string;
    price: string;
}

const products = await getItems<Product>({
    collection: "product"
});
</script>

Note that you specify an interface and type for the Product and pass this type to the getItems function as a Generic Type, so that the getItems function knows what kind of items it returns. This is a first class TypeScript support 🎉

Creating Items

To create a new product, your useDirectusItems composable also exports a createItems function. Inside of the pages/ directory, create and open an new.vue file:

vue
<template>
<button @click="createItems">Create items</button>
</template>

<script setup lang="ts">
const { createItems } = useDirectusItems();

interface Product {
    id: number;
    title: string;
    price: string;
}

const newProducts: Product[] = [
	{ title: "Banana", price: "0.29€" },
	{ title: "Vue.js Handbook", price: "29.99€" 
];

await createItems<Product>({
    collection: "product",
    items: newProducts
});
</script>
<template>
<button @click="createItems">Create items</button>
</template>

<script setup lang="ts">
const { createItems } = useDirectusItems();

interface Product {
    id: number;
    title: string;
    price: string;
}

const newProducts: Product[] = [
	{ title: "Banana", price: "0.29€" },
	{ title: "Vue.js Handbook", price: "29.99€" 
];

await createItems<Product>({
    collection: "product",
    items: newProducts
});
</script>

As you can see, the createItems method accepts an array with your item type (Product), so you can create many items at once.

Deleting Items

To delete specific items, you must pass the IDs of the items to the deleteItems function of useDirectusItems. Here is an illustration of how to use it:

vue
<script setup lang="ts">
const { deleteItems } = useDirectusItems();

const items = ["15", "20", "22"];
 await deleteItems({ collection: "product", items });
</script>
<script setup lang="ts">
const { deleteItems } = useDirectusItems();

const items = ["15", "20", "22"];
 await deleteItems({ collection: "product", items });
</script>

Updating Items

Use the updateItem function, you must provide the id and a partial items object with changes. Here is an illustration of how to use it:

vue
<script setup lang="ts">
const { updateItem } = useDirectusItems();

interface Product {
    id: number;
    title: string;
    price: string;
}

const product = {
   price: "199.99€"
}

const updatedProduct = await updateItem<Product>({
    collection: "product",
    id: 1,
    item: product
});
</script>
<script setup lang="ts">
const { updateItem } = useDirectusItems();

interface Product {
    id: number;
    title: string;
    price: string;
}

const product = {
   price: "199.99€"
}

const updatedProduct = await updateItem<Product>({
    collection: "product",
    id: 1,
    item: product
});
</script>

Authentication with nuxt-directus

An important topic for almost every web application is authentication, not everyone has and should have access to certain data.

Directus offers a user & permission management system, nuxt-directus offers as frontend counterpart the useDirectusAuth composable to easily build a login, or even a registration page.

useDirectusAuth implements the following functionality:

  • Register / Login
  • Invites
  • Password Reset
  • Token Refresh

Login Page

Create a new login.vue page in your pages/ directory, and open it. You will now use thelogin() function provided by useDirectusAuth:

vue
<template>
    <div>
        <h1>Login</h1>
        <input type="email" placeholder="Your E-Mail Address" v-model="email"/>
        <input type="password" placeholder="Your Password" v-model="password"/>
        <button @click="onSubmit">Login</button>
    </div>
</template>

<script setup lang="ts">
const { login } = useDirectusAuth();

const email = ref("");
const password = ref("");

const onSubmit = async () => {
	try {
		await login({ email: email.value, password: password.value });
	} catch (e) {}
};
</script>
<template>
    <div>
        <h1>Login</h1>
        <input type="email" placeholder="Your E-Mail Address" v-model="email"/>
        <input type="password" placeholder="Your Password" v-model="password"/>
        <button @click="onSubmit">Login</button>
    </div>
</template>

<script setup lang="ts">
const { login } = useDirectusAuth();

const email = ref("");
const password = ref("");

const onSubmit = async () => {
	try {
		await login({ email: email.value, password: password.value });
	} catch (e) {}
};
</script>

In the <script> section, you add the logic - an onSubmit function that gets triggered by the login button and sends a login request to Directus.

In your <template> section you have the button and two form inputs, containing the email address and the password.

After you created the login page, you can access it with your browser on http://localhost:3000/login (the port can change, check your nuxt console), and you will receive this:

Login form with email, password input and a login button

Show User Information

The button calls the onSubmit function on a click, but how will your application know that a user is logged in and the login was successful?

Let's add a user display so that the current user is displayed. For this purpose, you can use the useDirectusUser composable:

vue
<script setup lang="ts">
const { login } = useDirectusAuth();
const user = useDirectusUser(); 

const email = ref("");
const password = ref("");

const onSubmit = async () => {
  try {
    await login({ email: email.value, password: password.value });
  } catch (e) {}
};
</script>
<script setup lang="ts">
const { login } = useDirectusAuth();
const user = useDirectusUser(); 

const email = ref("");
const password = ref("");

const onSubmit = async () => {
  try {
    await login({ email: email.value, password: password.value });
  } catch (e) {}
};
</script>

Now you can access the user in the template area:

vue
<template>
    <div>
        <h1>Login</h1>
        <input type="email" placeholder="Your E-Mail Address" v-model="email"/>
        <input type="password" placeholder="Your Password" v-model="password"/>
        <button @click="onSubmit">Login</button>
    </div>
    <div style="margin-top: 55px" v-if="user"> 
        <h1>Current User</h1> 
        <pre>{{ user }}</pre> 
    </div> 
</template>
<template>
    <div>
        <h1>Login</h1>
        <input type="email" placeholder="Your E-Mail Address" v-model="email"/>
        <input type="password" placeholder="Your Password" v-model="password"/>
        <button @click="onSubmit">Login</button>
    </div>
    <div style="margin-top: 55px" v-if="user"> 
        <h1>Current User</h1> 
        <pre>{{ user }}</pre> 
    </div> 
</template>

And if your login was successful, you should see your user object on the page.

Register and Login

After login you have the possibility to fetch the user every time Nuxt runs with the autoFetch option and to check if the token is still active, and also it will refetch the useDirectusUser data.

With this informations you can build a middleware to protect your pages, see the nuxt-directus docs.

Register Page

The login page works for existing users in your Directus project. You will now build a registration form for new user creation.

Create and open a newpages/register.vue file. It looks similar to the login form, but this time your onSubmit function calls the register.

vue
<template>
    <div>
        <h1>Registration</h1>
        <input type="email" placeholder="Your E-Mail Address" v-model="email"/>
        <input type="password" placeholder="Your Password" v-model="password"/>
        <button @click="onSubmit">Register</button>
    </div>
</template>

<script setup lang="ts">
const { register } = useDirectusAuth();

const email = ref("");
const password = ref("");

const onSubmit = async () => {
  try {
    await register({ email: email.value, password: password.value,  });
    alert("Registered successfully");
  } catch (e) {}
};
</script>
<template>
    <div>
        <h1>Registration</h1>
        <input type="email" placeholder="Your E-Mail Address" v-model="email"/>
        <input type="password" placeholder="Your Password" v-model="password"/>
        <button @click="onSubmit">Register</button>
    </div>
</template>

<script setup lang="ts">
const { register } = useDirectusAuth();

const email = ref("");
const password = ref("");

const onSubmit = async () => {
  try {
    await register({ email: email.value, password: password.value,  });
    alert("Registered successfully");
  } catch (e) {}
};
</script>

After creating your page it should look almost exactly like your login page.

The login & register is now ready, if you want to know more about authentication, and especially how nuxt-directus works under the hood feel free to check out the documentation.

To log the user in directly after registration, combine the logic above - call the login function once after the user has been successfully created with the data the user has entered.

Files

nuxt-directus provides the useDirectusFiles composable, which contains two functions for working with files.

Get Files

The way you get the files is similar to all other composables. Import the getFiles function from the useDirectusFiles composable:

vue
<script setup>
const { getFiles } = useDirectusFiles();

const fetchFiles = async () => {
	const files = await getFiles({
		params: {
			{ limit: 10 },
		},
	});
};
</script>
<script setup>
const { getFiles } = useDirectusFiles();

const fetchFiles = async () => {
	const files = await getFiles({
		params: {
			{ limit: 10 },
		},
	});
};
</script>

Limit query

The limit option is a global search queries which you can use on Items too, checkout the DirectusQueryParams Type for more information about the search queries.

Thumbnails

For images that are located at Directus and should also be displayed, nuxt-directus provides the getThumbnail function which returns an image url src:

vue
<template>
  <div>
    <img :src="getThumbnail(fileId)" alt="original" />
  </div>
</template>

<script setup>
const fileId = "5e47b7e6-fd78-400c-821f-0dca4a176f4f";
const { getThumbnail } = useDirectusFiles();
</script>
<template>
  <div>
    <img :src="getThumbnail(fileId)" alt="original" />
  </div>
</template>

<script setup>
const fileId = "5e47b7e6-fd78-400c-821f-0dca4a176f4f";
const { getThumbnail } = useDirectusFiles();
</script>

Summary

nuxt-directus has eight integrated composables, in this post, you worked with four. While there is more to learn, you have learned the most important ones - you can now build beautiful Authentication pages, build an application based on your Directus Data models, Items and Collections.

If you want to learn more about nuxt-directus check out the documentation, if you have questions feel free to ask them on the Nuxt Discord or on GitHub as an Issue or Discussion.

Make it count

How helpful was this article?