DEV Community

Cover image for Building for the Edge with Nuxt.js and Strapi Integration
Theodore Kelechukwu Onyejiaku for Strapi

Posted on • Originally published at strapi.io

Building for the Edge with Nuxt.js and Strapi Integration

Introduction

With users accessing content from every corner of the globe, most servers fall short in delivering low-latency and high-performance experiences.

Thanks to Edge computing! Through Content Delivery Networks (CDNs), the Edge allows JavaScript to execute closer to end users.

Nuxt.js, a powerful Vue.js framework allows developers to gain a complete toolkit for building applications that can be deployed anywhere, including on edge platforms like Cloudflare Workers, Netlify Edge Functions, and Vercel through its Nitro engine.

This article explores how to build and deploy a Nuxt.js application at the edge while integrating Strapi for content management and authentication.

Video Resource

The complete video for this tutorial is available on YouTube.

In this video, Sebastien Chopin, the creator of Nuxt.js, explores the concept, benefits, and challenges of building for the edge.

What Is Edge Computing in JavaScript?

At its core, the Edge refers to a limited JavaScript runtime that runs on CDN nodes, which are used to serve static files. However, instead of just HTML and static files, you can now execute JavaScript at these edge locations.

What this means is that you can execute JavaScript where normally you would serve static files.

Let's discuss the benefits of using the Edge.

Key Benefits of Running Nuxt on the Edge

Here are some of the benefits of the Edge.

  • Runs milliseconds from end users (low latency)
  • Zero milliseconds cold start (no need to spawn virtual machines like in traditional serverless).
  • Request and context isolation thanks to the V8 engine. Thus, no shared state between requests.
  • Highly affordable. For example, you can make 100,000 free requests/day via Cloudflare. This is cheaper compared to serverless.

Common Limitations of JavaScript Edge Runtimes

The Edge also has its limitations which include:

  • Subset of Node.js and Browser API: There is no Node.js API support (limited access), no DOM manipulation, no HTTP server, no file system, etc. However, different providers are slowly supporting some Node.js APIs.
  • Small server size limit: You can't upload more than 10 MB gzip of JavaScript.

What is Edge.png

Top Edge Platforms for Deploying Nuxt.js Applications

You can deploy Nuxt.js to Cloudflare workers or other platforms once you have built your app.

After deploying your code to an Edge platform, your code will be replicated on many nodes. You can think of it like a load balancer but every node will be running your website.

Here are some Edge platforms you can deploy to:

  • AWS Lambda@Edge,
  • Bunny.net,
  • Cloudflare Pages/Workers,
  • Vercel Edge Functions,
  • Deno Deploy,
  • Fastly Comput,
  • Netlify Edge Functions,
  • Vercel Edge Functions,
  • etc.

As we mentioned above, the 2 limitations of Edge runtimes can pose a big issue. So, 3 years ago, Nuxt 3 was being developed to ensure you could deploy a Nuxt website to edge runtimes.

So, what is Nuxt.js?

What Is Nuxt.js? Vue Framework for Full-Stack Web Apps

Nuxt is a progressive web framework used to create full-stack applications with TypeScript and Vue.js.

It was created by Sebastian Chopin in October 2016. So far, it has achieved the following:

  • 57K+ stars on GitHub.
  • 3.3M+ downloads/month.
  • Used by startups and enterprises alike.

Top Features of Nuxt.js for Building Full-Stack Apps

Some features found in Next.js are also available in Nuxt.js. They include the following:

  • Server-Side Rendering: Nuxt provides you with server-side rendering with the option of disabling it. For example, you can disable it globally if you are just building a dashboard or at the root level for example:
export default defineNuxtConfig({ routeRules: { '/dashboard/**': { ssr: false } } }) 
Enter fullscreen mode Exit fullscreen mode
  • Pre-rendering: Nuxt.js supports pre-rendering to allow you to pre-render your whole website. Nuxt has an internal crawler that crawls your website to find links and generate them. Or you can specify the routes you want to render at built time or dynamically.
  • Routing and Layouts with automatic code splitting: Nuxt will ship the minimum amount of JavaScript, and then as you navigate further, more JavaScript will be downloaded.
  • Data fetching at the component level: Just as you can do suspense with Vue.js, you can do data fetching at the component level using Nuxt. This is very useful when you want to reuse data fetching and not be limited to the page level.
  • Protected routes: You can protect routes using Nuxt.js Middleware.
  • State management: Nuxt.js provides you with a basic state management composable even though there are plugins to provide you with State management. This allows you to share data between page components.
  • Server API routes: You can create API routes using Nuxt. However, you don't need to do this if you are using Strapi as a Headless CMS.
  • Layer system: Nuxt allows you to create a Nuxt app within a Nuxt app using the layers directory. This means that Nuxt provides you with a domain-driven design for a specific feature using layers or NPM packages. For example, an e-commerce, where you can have a cart layer, shop layer, product layer, and so on. Layers allow each team to work on a specific directory giving you the freedom to run only one specific layer depending on your choice.
  • Module Ecosystem (Nuxt Plugins): You can extend your Nuxt applications using modules. There are over 270+ modules or plugins currently that allow you to extend the features of Nuxt or integrate into various services.
  • Deploy Anywhere: You can deploy your Nuxt app anywhere. There is no vendor lock-in.

Nuxt Features.png

Essential Nuxt Modules and How to Integrate Strapi

Nuxt also comes with its own official modules so as to keep it as light as possible. These include the following:

  • @nuxt/content: This allows you to work with Markdowns especially if you are working on documentation, a portfolio, etc. This is basically a file-based CMS.
  • @nuxt/eslint: Linting integration.
  • @nuxt/fonts: Allows you to quickly add custom web fonts from Google or other providers with performance in mind.
  • @nuxt/icon: Gives you access to over 200,000 icons via Iconify.
  • @nuxt/image: Great for adding images. Ensures performance and provides support for many providers.
  • @nuxt/scripts: Developed with the Google Chrome Aurora team to improve script performance (e.g., A/B testing scripts) without slowing down the site).
  • @nuxt/ui: Useful development tools and UI components built on Radix UI and Tailwind CSS.

How to Install and Configure the Strapi Module in Nuxt.js

You can install any of the modules above using the command below:

npx nuxt module add <module> 
Enter fullscreen mode Exit fullscreen mode

Step 1: Install Strapi Nuxt Module

There is the Strapi module for Nuxt. You can install it using the command below:

npm nuxt module add strapi 
Enter fullscreen mode Exit fullscreen mode

Step 2: Set Strapi URL in the Environment Variable

The next step is to set the Strapi URL in the environment variable:


STRAPI_URL=http://localahost:1337

Step 3: Start Using the Strapi Vue Composables:

After installation, you can use the Vue composable in your code. The Nuxt module for Strapi integration supports authentication, fetching of collections, and so on.

const { find } = useStrapi(); const { login } = useStrapiAuth(); const user = useStrapiAuth(); // Example: fetch restaurants const restaurants = await find(`restaurants`); // Example: login await login({ identifier: "test@test.com", password: "password", }); 
Enter fullscreen mode Exit fullscreen mode

You can learn more about Strapi and Nuxt integration in these documentation links.

Nuxtjs official modules.png

How to Deploy Nuxt.js Apps to Edge Platforms like Cloudflare and Netlify

In order to make sure to support Nuxt.js edge deployment, Nuxt provides proxies or polyfills for Node.js dependencies automatically.

The Nuxt build output is optimized for runtime compatibility.

For example when you have a basic Nuxt application and you build for Cloudflare using the command below.

npx nuxt build --preset=cloudflare-module 
Enter fullscreen mode Exit fullscreen mode

The command is used to deploy Nuxt.js to Cloudflare Workers.

Here is what Nuxt will do with the command:

  • Create an output directory.
  • Inside the output directory, you will find your whole application with the server, components, routes, etc. included.
  • Produces a small build: ~700KB raw, ~227KB gzipped.
  • Supports cold starts of 4ms or less by creating context isolation and will start your Nuxt application server every time. This means that if a user calls your API, it won't load all your bundle, so as to make it as fast as possible.

Nuxt.js Build Presets For the Edge

How do you build for different Edge platforms? The Nuxt.js team has worked on a server engine so you don't have to worry.

You can use the preset for different platforms as shown below:

  • For Cloudflare Workers
nuxt build --preset-cloudflare_module 
Enter fullscreen mode Exit fullscreen mode
  • For Deno Deploy
nuxt build --preset-deno_deploy 
Enter fullscreen mode Exit fullscreen mode
  • For Netflify Edge Functions
nuxt build --preset-netlify_edge 
Enter fullscreen mode Exit fullscreen mode
  • For Vercel Edge Function
nuxt build --preset-vercel_edge 
Enter fullscreen mode Exit fullscreen mode

An example of how you would want to deploy to Cloudflare would look like this:

// Generate output format export default { async fetch(request){ // Your Nuxt code } } 
Enter fullscreen mode Exit fullscreen mode

Example: Server-Side Rendering with Nuxt.js with Dynamic Styling

Let's demonstrate Server-side rendering with Nuxt.js.

Say you create a basic Nuxt.js application that contains:

  • A main component (app.vue)
  • A public folder for static assets
  • A basic Nuxt configuration.

Render a random color each time the page is refreshed to demonstrate server-side rendering (SSR) in Nuxt.

// Path: ./app.vue <script setup> const colors = [ "red", "green", "blue", "yellow", "purple", "orange", "pink", "brown", ]; const color = colors[Math.floor(Math.random() * colors.length)]; </script>  <template> <h1 :style="{ color }">Hello Strapi!</h1> </template>  
Enter fullscreen mode Exit fullscreen mode

Here is what the page looks like. When you refresh, you will have a random color assigned to the title.

Render a Random Color Title.gif

Fixing Hydration Errors in Nuxt Server-Side Rendering

Due to Nuxt being a universal framework, it will server-render your application. Hydration errors can occur when the client and server render different initial values. So, when you navigate to your browser dev tool, you should see an error as shown below:

Astro Hydration Error.png

The error is that we have a different color happening on the client side and server side, a "blue" and "green" respectively. This is called hydration. So let's make this render only on the client side.

The solution for this would be to use a shared state value between client and server, similar to states in React or Next.js.

Here is the updated code:

<script setup> const colors = [ "red", "green", "blue", "yellow", "purple", "orange", "pink", "brown", ]; const color = useState( "color", () => colors[Math.floor(Math.random() * colors.length)] ); </script>  <template> <h1 :style="{ color }">Hello Strapi!</h1> </template>  
Enter fullscreen mode Exit fullscreen mode

The useState state management creates a variable that will be created by the server and reused by the client.

Let's deploy this basic app to the Edge.

Deploying Nuxt.js App to Cloudflare Edge

Run the command below to create the build for Cloudflare Pages:

npx nuxt build --preset=cloudflare-module 
Enter fullscreen mode Exit fullscreen mode

To deploy to production, run the command below:

npx wrangler deploy .output 
Enter fullscreen mode Exit fullscreen mode

The command installs wrangler which is for Cloudflare deployment.

Upon successful Nuxt.js Edge deployment, you should have a URL of your Nuxt project, with SSR on the Edge. And you should see that the app responded globally in less than 200ms. And you don't need to manage servers, as it automatically scales. Most importantly, it is closer to users.

Learn more about about deploying to Cloudflare.

How to Add Custom Fonts in Nuxt Using @nuxt/fonts Module

Let's make our basic app fancier by installing the nuxt-fonts module.

Run the command below inside your Nuxt application:

npx nuxt module add fonts 
Enter fullscreen mode Exit fullscreen mode

Once that is done, add the following styles to your code inside the app.vue file.

// Path: ./app.vue <script setup> const colors = [ "red", "green", "blue", "yellow", "purple", "orange", "pink", "brown", ]; const color = useState( "color", () => colors[Math.floor(Math.random() * colors.length)] ); </script>  <template> <h1 :style="{ color }">Hello Strapi!</h1> </template>  <style> body { font-family: "Pacifico", sans-serif; } </style>  
Enter fullscreen mode Exit fullscreen mode

This is what the font of your app should look like.

New Font in Nuxt.png

Now, when you build your Nuxt application using npm run build command, you will see that Nuxt will automatically download the fonts and store it. This means there won't be any API call to Google fonts. See image below.

Nuxt downloads fonts.png

Full Example: Implementing Strapi Authentication in Nuxt.js

Now, let's demonstrate how to integrate Strapi authentication using the nuxtjs/strapi module. Let's leverage Strapi authentication!

Step 1: Install the Strapi Module

Install the Strapi module developed by the Nuxt team by running the command below. Note that so far, the Strapi module didn't leverage the Strapi client library.

npx nuxt module add strapi 
Enter fullscreen mode Exit fullscreen mode

Step 2: Add Strapi URL to Nuxt.js .env

Add your Strapi API URL to the .env file of your Nuxt.js app and ensure your Strapi app is running.

STRAPI_URL=http://localhost:1337 
Enter fullscreen mode Exit fullscreen mode

Step 3: Display Authenticated User and Logout Button

To display an authenticated user, we will have to first get the user using the useStrapiUser() function. To check if a user is logged in, we will get the auth information using the useStrapiAuth() function.

// Path: ./.env // ... color variable and useState const auth = useStrapiAuth(); const user = useStrapiUser(); <template> <h1 :style="{ color }">Hello Strapi!</h1>  <div v-if="user"> <pre >{{ user }}</pre>  <button @click="auth.logout">Logout</button>  </div>  // ... other codes </template>  // ... styles 
Enter fullscreen mode Exit fullscreen mode

In the code above, we did the following:

  • Display the user if the user is authenticated.
  • Add a button to log out the user.

When you refresh your Nuxt app, you will notice that the user is not authenticated. So, let's add a way to authenticate the user by creating a Sign-up form.

Step 4: Create Nuxt.js Form for User Signup

Create a credentials object that should contain username, email, and password variables for a user to sign up.

// Path: ./app.vue // ... other codes const credentials = reactive({ username: "", email: "", password: "", }); // ... other codes 
Enter fullscreen mode Exit fullscreen mode

Next, create a form to be displayed if the user is not authenticated. This should call the handleSignUp function which will handle the form submission. Ensure you pass in the credentials to the appropriate form inputs.

// Path: ./app.vue // ... other codes <div v-else> <form @submit.prevent="handleSignUp"> <h2>Signup</h2>  <input v-model="credentials.username" type="text" placeholder="Username" required /> <input v-model="credentials.email" type="email" placeholder="Email" required /> <input v-model="credentials.password" type="password" placeholder="Password" required /> <button type="submit">Signup</button>  </form> </div>  // ... other codes 
Enter fullscreen mode Exit fullscreen mode

Now, this is what your app should look like:

Signup Form.png

Step 5: Create Nuxt.js Signup Function

Next, create the handleSignUp() function above to handle the signup form submission.

// Path: ./app.vue // ... other codes async function handleSignUp() { await auth.register(credentials).catch((err) => alert(err.error?.message)); } // ... other codes 
Enter fullscreen mode Exit fullscreen mode

Now, let's sign up a new user.

signup and logout.gif

As you can see we have signed up a new user in the Strapi backend.

Now, let's log in as a user.

Step 6: Create Nuxt.js Login Form

Create a login form for users to enter their identifier and password.

// Path: ./app.vue // ... other codes <form @submit.prevent="handleLogin"> <h2>Login</h2>  <input v-model="credentials.username" type="text" placeholder="Username or Email" required /> <input v-model="credentials.password" type="password" placeholder="Password" required /> <button type="submit">Login</button> </form>  // ... other codes 
Enter fullscreen mode Exit fullscreen mode

Create Nuxt.js Login Form

Create a function to handle the login form submission.

// Path: ./app.vue // ... other codes async function handleLogin() { await auth .login({ identifier: credentials.username, password: credentials.password, }) .catch((err) => alert(err.error?.message)); } // ... other codes 
Enter fullscreen mode Exit fullscreen mode

Now, we can log in as a user as shown below:

Login and Logout a User.gif

Complete Code: GitHub Repo

Here is the complete code for our basic Nuxt app which we integrated with Strapi using the Nuxt Strapi module.

// Path: ./app.vue <script setup> const colors = [ "red", "green", "blue", "yellow", "purple", "orange", "pink", "brown", ]; const color = useState( "color", () => colors[Math.floor(Math.random() * colors.length)] ); const auth = useStrapiAuth(); const user = useStrapiUser(); const credentials = reactive({ username: "", email: "", password: "", }); async function handleSignUp() { await auth.register(credentials).catch((err) => alert(err.error?.message)); } async function handleLogin() { await auth .login({ identifier: credentials.username, password: credentials.password, }) .catch((err) => alert(err.error?.message)); } </script>  <template> <h1 :style="{ color }">Hello Strapi!</h1>  <div v-if="user"> <pre>{{ user }}</pre>  <button @click="auth.logout">Logout</button>  </div>  <div v-else> <form @submit.prevent="handleSignUp"> <h2>Signup</h2>  <input v-model="credentials.username" type="text" placeholder="Username" required /> <input v-model="credentials.email" type="email" placeholder="Email" required /> <input v-model="credentials.password" type="password" placeholder="Password" required /> <button type="submit">Signup</button>  </form>  <form @submit.prevent="handleLogin"> <h2>Login</h2>  <input v-model="credentials.username" type="text" placeholder="Username or Email" required /> <input v-model="credentials.password" type="password" placeholder="Password" required /> <button type="submit">Login</button>  </form>  </div> </template>  <style> h1 { font-family: "Pacifico", sans-serif; } </style>  
Enter fullscreen mode Exit fullscreen mode

You can also find the complete code in this GitHub repo.

Nitro: The Edge-Agnostic Engine

If you're not a Vue fan, no problem. Nuxt’s core server and build engine is called Nitro.

Nitro is a framework-agnostic engine responsible for all the route handlers, build presets, and minification of outputs.

Used in:

You can even create your own web framework using Nitro.

Summary

Nuxt’s Edge compatibility, powered by its framework-agnostic Nitro engine, gives you the ability to:

  • Optimize performance with cold start times near zero
  • Serve content close to users across the globe
  • Leverage flexible features like modular architecture, pre-rendering, and automatic code-splitting
  • Integrate with modern tools like Strapi, Google Fonts, and custom UI libraries—without compromising speed or privacy

If you’re deploying a full-stack application, connecting to a headless CMS, or simply experimenting with SSR, Nuxt makes edge deployment seamless and powerful.

Try building and deploying with a preset like Cloudflare, and join the growing ecosystem of developers building for the edge.

Learn more about Nuxt through its documentation at nuxt.com. You can also explore more Nuxt repositories on github.com/nuxt.

Top comments (0)