Skip to content

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:

  1. Create a new Nuxt project using the scaffolding tool:
    Terminal window
    npx nuxi@latest init my-nuxt-app
    cd my-nuxt-app
    npm install
  2. Start the development server:
    Terminal window
    npm run dev
  3. Visit http://localhost:3000 to see your app running. Nuxt will automatically rebuild as you make changes.
  4. Explore the generated project structure with pages, components, and configuration files.
  5. Build the application for production to ensure it compiles correctly:
    Terminal window
    npm run build
    npm run preview

Sample Code Examples

Basic Nuxt Page with Vue 3 Composition API

Here’s a complete example with reactive state and component composition:

pages/index.vue
<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

server/api/health.ts
export default defineEventHandler(async (event) => {
return {
status: 'healthy',
timestamp: new Date().toISOString(),
uptime: process.uptime()
};
});
server/api/users/index.ts
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

composables/useUsers.ts
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
};
};
pages/users.vue
<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.json

Deploying 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.

  1. Build your Nuxt application for production to ensure everything compiles correctly:
    Terminal window
    npm run build

    Verify the .output folder is created with your built application.

  2. Push your Nuxt application to a GitHub repository with all your source code, `pages`, `components`, `server`, `package.json`, and `package-lock.json` files.
  3. Log in to your Klutch.sh dashboard.
  4. Create a new project and give it a name (e.g., "My Nuxt App").
  5. 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)
  6. Click "Create" to deploy. Klutch.sh will automatically detect your Node.js project, install dependencies, build your Nuxt application, and start it.
  7. 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.

  1. Create a `Dockerfile` in your project root:
    # Multi-stage build for optimized Nuxt deployment
    FROM node:18-alpine AS builder
    WORKDIR /app
    # Copy package files
    COPY package*.json ./
    # Install dependencies
    RUN npm ci
    # Copy source code
    COPY . .
    # Build Nuxt application
    RUN npm run build
    # Production stage
    FROM node:18-alpine
    WORKDIR /app
    # Copy package files
    COPY package*.json ./
    # Install only production dependencies
    RUN npm ci --only=production
    # Copy built application from builder
    COPY --from=builder /app/.output ./.output
    # Set production environment
    ENV NODE_ENV=production
    # Expose port (must match your app's listening port)
    EXPOSE 3000
    # Health check
    HEALTHCHECK --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 application
    CMD ["node", ".output/server/index.mjs"]
  2. Create a `.dockerignore` file to exclude unnecessary files from the Docker build:
    node_modules
    npm-debug.log
    .nuxt
    .output
    .git
    .gitignore
    .env
    .env.local
    README.md
    .vscode
    .idea
    .DS_Store
    dist
  3. Push your code (with Dockerfile and .dockerignore) to GitHub.
  4. 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.

  5. 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 configuration
NITRO_PRERENDER=false
NODE_ENV=production
# API configuration
NUXT_PUBLIC_API_URL=https://api.example.com
API_SECRET=your_secret_key
# Database connection
DATABASE_URL=postgresql://user:password@db.example.com:5432/mydb
# Third-party services
STRIPE_PUBLIC_KEY=pk_live_xxx
STRIPE_SECRET_KEY=sk_live_xxx
# Analytics
NUXT_PUBLIC_GA_ID=G-xxx
# Features
LOG_LEVEL=info
ENABLE_LOGGING=true

Using Environment Variables in Your App

server/api/config.ts
export default defineEventHandler(async (event) => {
return {
apiUrl: useRuntimeConfig().public.apiUrl,
environment: process.env.NODE_ENV,
hasDatabase: !!process.env.DATABASE_URL
};
});
nuxt.config.ts
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 build
START_COMMAND: node .output/server/index.mjs

Set 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:

nuxt.config.ts
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:

nuxt.config.ts
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

  1. Use Hybrid Rendering - Combine SSR with prerendering for best performance
  2. Optimize Images - Use Nuxt Image component for automatic optimization
  3. Code Splitting - Nuxt automatically splits code by route
  4. Composables Caching - Cache composable results appropriately
  5. Database Connection Pooling - Manage connections efficiently
  6. API Route Caching - Cache API responses when possible
  7. 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.json has valid build and start scripts
  • 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 .output folder is properly generated

Build Fails with Module Errors

Problem - Build fails with “Cannot find module” errors

Solution:

  • Ensure your package.json is in the root directory
  • Verify all dependencies are listed correctly
  • Check that package-lock.json exists and is up to date
  • Run npm install locally to verify dependencies work
  • Remove node_modules and .nuxt, then run fresh npm 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


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.