Nuxt is the full-stack framework for Vue.js. It supports server-side rendering, static generation, and hybrid rendering out of the box. Built on the Nitro server engine, Nuxt provides file-based routing, auto-imports, and a powerful server directory for building APIs — all with zero configuration. Deploying a Nuxt application to production typically involves configuring servers, build presets, and SSL certificates.
With Out Plane, you can deploy your Nuxt application in under a minute. This guide shows you exactly how.
What You'll Need
Before starting, make sure you have:
- Node.js 20+ installed on your machine
- npm (comes with Node.js)
- A GitHub account
- A Nuxt application in a GitHub repository
Don't have Node.js installed? Download it from nodejs.org:
- Windows: Download the LTS installer from nodejs.org
- macOS: Use
brew install nodeor download from nodejs.org - Linux: Run
curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash - && sudo apt install -y nodejs(Ubuntu/Debian)
Once Node.js is installed, create a new Nuxt project:
npx nuxi@latest init my-nuxt-app
cd my-nuxt-appIf you don't have a Nuxt app yet, use our example below.
Quick Start: Sample Nuxt Application
Here's a minimal Nuxt application you can use. Create a new project with the Nuxt CLI:
npx nuxi@latest init my-nuxt-app
cd my-nuxt-app
npm installThe CLI generates a project with the essential configuration. Update the following files for a production-ready application.
Replace pages/index.vue with a simple page that fetches data from an API route:
<script setup lang="ts">
const { data } = await useFetch('/api/health')
</script>
<template>
<main style="padding: 2rem; font-family: system-ui">
<h1>Hello from Nuxt!</h1>
<p>Deployed on Out Plane</p>
<p v-if="data">Server status: {{ data.status }}</p>
</main>
</template>Create a Nitro API route at server/api/health.ts:
export default defineEventHandler(() => {
return {
status: 'healthy',
timestamp: new Date().toISOString(),
}
})Nitro auto-registers files in the server/api/ directory as API endpoints. No router configuration needed.
Update nuxt.config.ts — no special configuration is needed for Node.js deployment since Nitro defaults to the node-server preset:
export default defineNuxtConfig({
compatibilityDate: '2025-01-01',
devtools: { enabled: false },
})Create a Dockerfile in the project root:
# Build stage
FROM node:20-alpine AS builder
WORKDIR /app
COPY package.json package-lock.json* ./
RUN npm ci
COPY . .
RUN npm run build
# Production stage
FROM node:20-alpine
WORKDIR /app
ENV NODE_ENV=production
COPY --from=builder /app/.output ./.output
EXPOSE 3000
ENV NITRO_PORT=3000
ENV NITRO_HOST=0.0.0.0
CMD ["node", ".output/server/index.mjs"]The Nitro server engine compiles your entire application into a self-contained .output directory. The production image only needs this directory to run — no node_modules required.
Push this code to a GitHub repository, and you're ready to deploy.
Deploy in 3 Steps
Step 1: Connect Your Repository
- Go to console.outplane.com
- Sign in with your GitHub account
- Select your Nuxt repository from the list
Out Plane automatically detects your application and configures the build process.
Step 2: Configure Your Application
Configure the following settings in the create application form:
Build Method
Select how Out Plane should build your application:
- Dockerfile (Recommended): Uses the multi-stage Dockerfile above for optimal image size. The Nitro output is self-contained, producing very small production images.
- Buildpacks: Automatically detects Node.js and runs
npm run build. Works for simpler Nuxt applications.
For production Nuxt applications, Dockerfile is the recommended approach because it leverages Nitro's self-contained output for minimal image sizes.
Basic Settings
- Port: Set to
3000 - Branch: Select
mainor your preferred branch - Region: Choose the region closest to your users
Environment Variables (Optional)
If your application uses environment-specific configuration, add them here. Nuxt uses the NUXT_ prefix for runtime configuration:
- Runtime config: Variables prefixed with
NUXT_override values inruntimeConfigat runtime - Public runtime config: Variables prefixed with
NUXT_PUBLIC_are exposed to the client
Add variables using the Add button or Raw Edit for bulk entry:
DATABASE_URL=postgres://user:password@host/database
NUXT_API_SECRET=your-api-secret
NUXT_PUBLIC_APP_URL=https://your-app.outplane.appStep 3: Deploy
Click Deploy Application and watch the build process:
- Queued → Waiting for resources
- Building → Installing dependencies, running
nuxt build - Deploying → Starting your Nuxt application
- Ready → Your app is live
Once the status shows Ready, your application is live. You can find your application URL at the top of the deployment page. Click the URL to open your Nuxt app in a new tab. SSL is automatically configured.
Production Best Practices
Runtime Config vs App Config
Nuxt provides two ways to configure your application. Use runtime config for values that change between environments, and app config for values set at build time:
// nuxt.config.ts
export default defineNuxtConfig({
runtimeConfig: {
// Server-only (overridden by NUXT_API_SECRET env var)
apiSecret: '',
// Public (overridden by NUXT_PUBLIC_API_BASE env var)
public: {
apiBase: '/api',
},
},
})Access runtime config in your application:
<script setup lang="ts">
const config = useRuntimeConfig()
// Client: config.public.apiBase
// Server: config.apiSecret
</script>Nitro Presets
Nitro defaults to the node-server preset, which is ideal for container deployments. If you need a different output format, set the preset in nuxt.config.ts:
export default defineNuxtConfig({
nitro: {
preset: 'node-server', // Default, best for Docker
},
})Do not change this preset unless you have a specific reason. The node-server preset works best with Out Plane.
Auto-Imports and Composables
Nuxt auto-imports Vue composables, utility functions, and your own composables from the composables/ directory. This means you don't need explicit import statements:
<script setup lang="ts">
// useState, useFetch, useRuntimeConfig are auto-imported
const count = useState('counter', () => 0)
const { data } = await useFetch('/api/items')
const config = useRuntimeConfig()
</script>Custom composables in composables/ are also auto-imported:
// composables/useApi.ts
export const useApi = () => {
const config = useRuntimeConfig()
const fetch = async (path: string) => {
return await $fetch(`${config.public.apiBase}${path}`)
}
return { fetch }
}Server Middleware
Use Nitro server middleware for request processing that runs before your API routes:
// server/middleware/log.ts
export default defineEventHandler((event) => {
console.log(`${event.method} ${getRequestURL(event)}`)
})Middleware files in server/middleware/ run automatically on every request. Use them for logging, authentication, or request transformation.
Connecting a Database
Most Nuxt applications need a database. Out Plane provides managed PostgreSQL:
- Go to Databases in the sidebar
- Click Create Database
- Select PostgreSQL version and region
- Copy the connection URL
Add the connection URL as an environment variable:
DATABASE_URL=postgres://user:password@host:5432/databaseUse it in your Nuxt application with Drizzle ORM in the server/ directory:
npm install drizzle-orm postgres
npm install -D drizzle-kitDefine your schema:
// server/database/schema.ts
import { pgTable, serial, text, timestamp } from 'drizzle-orm/pg-core'
export const items = pgTable('items', {
id: serial('id').primaryKey(),
name: text('name').notNull(),
createdAt: timestamp('created_at').defaultNow(),
})Create a database utility:
// server/utils/db.ts
import { drizzle } from 'drizzle-orm/postgres-js'
import postgres from 'postgres'
const client = postgres(process.env.DATABASE_URL!)
export const db = drizzle(client)Create an API route that fetches from the database:
// server/api/items.ts
import { db } from '../utils/db'
import { items } from '../database/schema'
export default defineEventHandler(async () => {
const allItems = await db.select().from(items).limit(50)
return allItems
})Files in server/utils/ are auto-imported in your server routes, so db is available without explicit imports.
Custom Domain Setup
Replace the default .outplane.app URL with your own domain:
- Navigate to Domains
- Click Map Domain
- Enter your domain (e.g.,
app.yourdomain.com) - Add the DNS records shown to your domain registrar
Update your NUXT_PUBLIC_APP_URL environment variable to reflect the new domain. SSL certificates are automatically provisioned once DNS propagates.
Monitoring Your Application
After deployment, monitor your Nuxt application:
- Logs: View real-time application logs including server-side rendering logs and Nitro request logs
- Metrics: Track CPU, memory, and network usage
- HTTP Logs: Analyze incoming requests, response times, and status codes
Access these from the sidebar in your application dashboard.
Troubleshooting
Nitro Preset Issues
Verify the correct preset is configured. For Docker deployments on Out Plane, use the default node-server preset. If you previously set a different preset (like vercel or netlify), remove it or change it to node-server:
export default defineNuxtConfig({
nitro: {
preset: 'node-server',
},
})Runtime Config Not Available
Use the NUXT_ prefix for environment variables. Nuxt maps environment variables to runtime config using the NUXT_ prefix. For nested values, use double underscores:
# Maps to runtimeConfig.apiSecret
NUXT_API_SECRET=your-secret
# Maps to runtimeConfig.public.apiBase
NUXT_PUBLIC_API_BASE=https://api.example.com
# Maps to runtimeConfig.database.host
NUXT_DATABASE_HOST=localhostIf runtime config values are still empty, verify that you defined them in nuxt.config.ts first. Environment variables only override existing keys.
Build Errors
Run npm run build locally before deploying. Common build failures include missing dependencies, TypeScript errors, and invalid imports. Check your application logs for specific error messages.
If the build fails with memory errors, set NODE_OPTIONS in your environment:
NODE_OPTIONS=--max-old-space-size=4096Hydration Mismatches
Ensure server and client render the same content. Hydration errors occur when the HTML rendered on the server doesn't match what the client expects. Common causes:
- Using
Date.now()or random values withoutuseState - Accessing
windowordocumentduring SSR - Conditional rendering based on client-only state
Use the <ClientOnly> component for client-specific content:
<template>
<ClientOnly>
<BrowserOnlyComponent />
</ClientOnly>
</template>API Route 404s
Verify the file path matches the expected URL. Nitro maps files in server/api/ to URLs automatically:
server/api/health.ts→/api/healthserver/api/items/index.ts→/api/itemsserver/api/items/[id].ts→/api/items/:id
Make sure the file is in the correct directory and uses the right naming convention. Restart the dev server after adding new API routes.
Next Steps
Your Nuxt application is now deployed and running in production. Here's what to explore next:
- Scale your application: Adjust instance types and auto-scaling settings for higher traffic
- Set up CI/CD: Enable automatic deployments on every git push
- Add monitoring: Integrate with external monitoring tools via Out Plane's metrics export
- Configure caching: Add Redis for session storage and Nitro route caching
Summary
Deploying a Nuxt application to Out Plane takes three steps:
- Connect your GitHub repository
- Configure port (3000), environment variables with
NUXT_prefix, and build method - Deploy and get your live URL with automatic HTTPS
No server configuration, no manual SSL setup, no infrastructure management. Full support for server-side rendering, Nitro API routes, and hybrid rendering.
Ready to deploy your Nuxt application? Get started with Out Plane and receive $20 in free credit.