Deploying a Nuxt App
Nuxt is a powerful, production-ready Vue.js framework for building fast, scalable, and SEO-friendly web applications. With built-in support for server-side rendering (SSR), static site generation (SSG), hybrid rendering modes, file-based routing, automatic code splitting, and a comprehensive module ecosystem, Nuxt simplifies the creation of sophisticated web applications. From content-driven websites to complex interactive applications, Nuxt provides the tools and performance optimizations needed for modern web development at scale.
This comprehensive guide walks you through deploying a Nuxt application to Klutch.sh, covering both automatic Nixpacks-based deployments and Docker-based deployments. You’ll learn installation steps, explore sample code, configure environment variables, and discover best practices for production deployments.
Table of Contents
- Prerequisites
- Getting Started: Install Nuxt
- Sample Code Examples
- Project Structure
- Deploying Without a Dockerfile (Nixpacks)
- Deploying With a Dockerfile
- Environment Variables & Configuration
- Rendering Modes & Deployment
- Performance & Optimization
- Troubleshooting
- Resources
Prerequisites
To deploy a Nuxt application on Klutch.sh, ensure you have:
- Node.js 18 or higher - Nuxt requires a modern Node.js version for optimal performance
- npm or yarn - For managing dependencies
- Git - For version control
- GitHub account - Klutch.sh integrates with GitHub for continuous deployments
- Klutch.sh account - Sign up for free
Getting Started: Install Nuxt
Create a New Nuxt Project
Follow these steps to create and set up a new Nuxt application:
-
Create a new Nuxt project using the scaffolding tool:
Terminal window npx nuxi@latest init my-nuxt-appcd my-nuxt-appnpm install -
Start the development server:
Terminal window npm run dev - Visit http://localhost:3000 to see your app running. Nuxt will automatically rebuild as you make changes.
- Explore the generated project structure with pages, components, and configuration files.
-
Build the application for production to ensure it compiles correctly:
Terminal window npm run buildnpm run preview
Sample Code Examples
Basic Nuxt Page with Vue 3 Composition API
Here’s a complete example with reactive state and component composition:
<template> <div class="min-h-screen bg-gradient-to-b from-blue-50 to-white p-8"> <div class="max-w-4xl mx-auto"> <h1 class="text-4xl font-bold mb-4">Welcome to Nuxt on Klutch.sh!</h1> <p class="text-lg text-gray-700 mb-8"> This is a modern Nuxt application deployed on Klutch.sh. </p> <p class="text-2xl font-semibold">Counter: {{ count }}</p> <button @click="count++" class="mt-4 px-6 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700" > Increment </button> </div> </div></template>
<script setup lang="ts">import { ref } from 'vue';
const count = ref(0);</script>Nuxt API Routes
export default defineEventHandler(async (event) => { return { status: 'healthy', timestamp: new Date().toISOString(), uptime: process.uptime() };});export default defineEventHandler(async (event) => { if (event.node.req.method === 'GET') { return [ { id: 1, name: 'John Doe', email: 'john@example.com' }, { id: 2, name: 'Jane Smith', email: 'jane@example.com' } ]; }
if (event.node.req.method === 'POST') { const body = await readBody(event); return { id: Math.floor(Math.random() * 10000), ...body, created: new Date().toISOString() }; }});Nuxt with Composables and Store
export const useUsers = async () => { const users = ref([]); const loading = ref(false); const error = ref(null);
const fetchUsers = async () => { loading.value = true; try { const data = await $fetch('/api/users'); users.value = data; } catch (e) { error.value = e; } finally { loading.value = false; } };
onMounted(() => { fetchUsers(); });
return { users: readonly(users), loading: readonly(loading), error: readonly(error), fetchUsers };};<template> <div class="p-8"> <h1 class="text-3xl font-bold mb-6">Users</h1>
<div v-if="loading" class="text-gray-600">Loading...</div>
<div v-if="error" class="text-red-600"> Error: {{ error.message }} </div>
<div v-else class="grid gap-4"> <div v-for="user in users" :key="user.id" class="border p-4 rounded-lg"> <h2 class="font-semibold">{{ user.name }}</h2> <p class="text-gray-600">{{ user.email }}</p> </div> </div> </div></template>
<script setup>const { users, loading, error, fetchUsers } = await useUsers();</script>Project Structure
A typical Nuxt project has this structure:
my-nuxt-app/├── app.vue├── nuxt.config.ts├── tsconfig.json├── pages/│ ├── index.vue│ └── users.vue├── components/│ ├── Header.vue│ └── Footer.vue├── composables/│ ├── useUsers.ts│ └── useAuth.ts├── server/│ ├── api/│ │ ├── health.ts│ │ └── users/│ │ └── index.ts│ └── middleware/│ └── auth.ts├── public/│ └── images/├── .env├── .gitignore├── package.json└── package-lock.jsonDeploying Without a Dockerfile
Klutch.sh uses Nixpacks to automatically detect and build your Nuxt application. This is the simplest deployment option that requires no additional configuration files.
-
Build your Nuxt application for production to ensure everything compiles correctly:
Terminal window npm run buildVerify the
.outputfolder is created with your built application. - Push your Nuxt application to a GitHub repository with all your source code, `pages`, `components`, `server`, `package.json`, and `package-lock.json` files.
- Log in to your Klutch.sh dashboard.
- Create a new project and give it a name (e.g., "My Nuxt App").
-
Create a new app with the following configuration:
- Repository - Select your Nuxt GitHub repository and the branch to deploy
- Traffic Type - Select HTTP (for web applications serving HTTP traffic)
- Internal Port - Set to 3000 (the default port for Nuxt applications)
- Region - Choose your preferred region for deployment
- Compute - Select the appropriate compute resource size
- Instances - Choose how many instances to run (start with 1 for testing)
- Environment Variables - Add any environment variables your app needs (API keys, database URLs, secrets, etc.)
If you need to customize the start command or build process, you can set Nixpacks environment variables:
START_COMMAND: Override the default start command (e.g.,node .output/server/index.mjs)BUILD_COMMAND: Override the default build command (e.g.,npm run build)
- Click "Create" to deploy. Klutch.sh will automatically detect your Node.js project, install dependencies, build your Nuxt application, and start it.
- Once deployed, your app will be available at a URL like `example-app.klutch.sh`. Test it by visiting the URL in your browser and checking the health endpoint at `/api/health`.
Deploying With a Dockerfile
If you prefer more control over the build and runtime environment, you can use a Dockerfile. Klutch.sh will automatically detect and use any Dockerfile in your repository’s root directory.
-
Create a `Dockerfile` in your project root:
# Multi-stage build for optimized Nuxt deploymentFROM node:18-alpine AS builderWORKDIR /app# Copy package filesCOPY package*.json ./# Install dependenciesRUN npm ci# Copy source codeCOPY . .# Build Nuxt applicationRUN npm run build# Production stageFROM node:18-alpineWORKDIR /app# Copy package filesCOPY package*.json ./# Install only production dependenciesRUN npm ci --only=production# Copy built application from builderCOPY --from=builder /app/.output ./.output# Set production environmentENV NODE_ENV=production# Expose port (must match your app's listening port)EXPOSE 3000# Health checkHEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \CMD node -e "require('http').get('http://localhost:3000/api/health', (r) => {if (r.statusCode !== 200) throw new Error(r.statusCode)})"# Start the applicationCMD ["node", ".output/server/index.mjs"]
-
Create a `.dockerignore` file to exclude unnecessary files from the Docker build:
node_modulesnpm-debug.log.nuxt.output.git.gitignore.env.env.localREADME.md.vscode.idea.DS_Storedist
- Push your code (with Dockerfile and .dockerignore) to GitHub.
-
Follow the same deployment steps as the Nixpacks method:
- Log in to Klutch.sh
- Create a new project
- Create a new app pointing to your GitHub repository
- Set the traffic type to HTTP and internal port to 3000
- Add any required environment variables
- Click “Create”
Klutch.sh will automatically detect your Dockerfile and use it to build and deploy your application.
- Your deployed app will be available at `example-app.klutch.sh` once the build and deployment complete.
Environment Variables & Configuration
Nuxt applications use environment variables for configuration. Set these in the Klutch.sh dashboard during app creation or update them afterward.
Common Environment Variables
# Server configurationNITRO_PRERENDER=falseNODE_ENV=production
# API configurationNUXT_PUBLIC_API_URL=https://api.example.comAPI_SECRET=your_secret_key
# Database connectionDATABASE_URL=postgresql://user:password@db.example.com:5432/mydb
# Third-party servicesSTRIPE_PUBLIC_KEY=pk_live_xxxSTRIPE_SECRET_KEY=sk_live_xxx
# AnalyticsNUXT_PUBLIC_GA_ID=G-xxx
# FeaturesLOG_LEVEL=infoENABLE_LOGGING=trueUsing Environment Variables in Your App
export default defineEventHandler(async (event) => { return { apiUrl: useRuntimeConfig().public.apiUrl, environment: process.env.NODE_ENV, hasDatabase: !!process.env.DATABASE_URL };});export default defineNuxtConfig({ runtimeConfig: { // Private keys only accessible on server apiSecret: process.env.API_SECRET, database: { url: process.env.DATABASE_URL }, // Public keys exposed to the client public: { apiUrl: process.env.NUXT_PUBLIC_API_URL || 'http://localhost:3000/api', gaId: process.env.NUXT_PUBLIC_GA_ID } }});Customizing Build and Start Commands with Nixpacks
If using Nixpacks deployment without a Dockerfile, you can customize build and start commands by setting environment variables:
BUILD_COMMAND: npm run buildSTART_COMMAND: node .output/server/index.mjsSet these as environment variables during app creation on Klutch.sh.
Rendering Modes & Deployment
Nuxt supports multiple rendering modes that affect your deployment:
Server-Side Rendering (SSR)
Default mode with full server-side rendering for SEO and dynamic content:
export default defineNuxtConfig({ ssr: true, nitro: { prerender: { crawlLinks: true, routes: ['/sitemap.xml'], ignore: ['/admin'] } }});Hybrid Rendering
Mix of static and dynamic routes for optimal performance:
export default defineNuxtConfig({ routeRules: { // Prerender home and static pages '/': { prerender: true }, '/about': { prerender: true }, '/blog/**': { swr: 3600 }, // Revalidate every hour '/api/**': { cache: { maxAge: 60 * 10 } }, // Cache API routes '/admin/**': { ssr: false } // Client-side only }});Performance Optimization Tips
- Use Hybrid Rendering - Combine SSR with prerendering for best performance
- Optimize Images - Use Nuxt Image component for automatic optimization
- Code Splitting - Nuxt automatically splits code by route
- Composables Caching - Cache composable results appropriately
- Database Connection Pooling - Manage connections efficiently
- API Route Caching - Cache API responses when possible
- Middleware Optimization - Keep middleware fast and focused
Troubleshooting
Application Won’t Start
Problem - Deployment completes but the app shows as unhealthy
Solution:
- Verify your Nuxt app builds locally:
npm run build - Check that
package.jsonhas validbuildandstartscripts - Ensure the app listens on port 3000
- Check application logs in the Klutch.sh dashboard for error messages
- Verify all environment variables are set correctly in the dashboard
- Check that
.outputfolder is properly generated
Build Fails with Module Errors
Problem - Build fails with “Cannot find module” errors
Solution:
- Ensure your
package.jsonis in the root directory - Verify all dependencies are listed correctly
- Check that
package-lock.jsonexists and is up to date - Run
npm installlocally to verify dependencies work - Remove
node_modulesand.nuxt, then run freshnpm install
Routes Not Working
Problem - Pages or API routes don’t work after deployment
Solution:
- Verify files are in correct locations (
pages/,server/api/) - Check file naming conventions (kebab-case or camelCase)
- Ensure dynamic routes have correct bracket syntax:
[id].vue - Test routes locally before deploying
High Memory Usage
Problem - App uses excessive memory and gets killed
Solution:
- Check for memory leaks in components or composables
- Implement proper cleanup in lifecycle hooks
- Limit data fetching and caching
- Monitor build size with
npm run build - Consider upgrading compute tier
- Implement pagination for large datasets
Slow Page Load Times
Problem - Pages load slowly despite Nuxt optimization
Solution:
- Enable prerendering for static pages
- Implement hybrid rendering for better performance
- Optimize images using Nuxt Image component
- Enable caching for API routes
- Check database query performance
- Consider implementing service workers for offline support
Resources
- Nuxt Official Documentation
- Nuxt Getting Started Guide
- Nuxt Rendering Modes Guide
- Nuxt Directory Structure
- Nuxt Server Routes and API
- Nixpacks Documentation
- Klutch.sh Dashboard
Summary
Deploying a Nuxt application on Klutch.sh is straightforward whether you choose Nixpacks or Docker. Both methods provide reliable, scalable hosting for your modern Vue.js applications. Start with Nixpacks for simplicity and rapid deployments, or use Docker for complete control over your build environment. With Nuxt’s powerful rendering modes, hybrid rendering capabilities, and Klutch.sh’s automatic scaling and load balancing, you can deploy your application from development to production and scale it to serve millions of users efficiently.