1. Deployment Targets
| Presets | Output | Use cases |
|---|---|---|
| node-server | Node.js server | VPS, Docker, PM2 |
| static. static | Static HTML | Netlify, GitHub Pages |
| cloudflare-pages | Edge Workers | Cloudflare |
| vercel | Serverless | Vercel |
| netlify | Serverless | Netflix |
// nuxt.config.ts
export default defineNuxtConfig({
// Auto-detect hoặc set thủ công
nitro: {
preset: 'node-server', // 'cloudflare-pages' | 'vercel' | ...
},
})
2. Docker Deployment
# Dockerfile
FROM node:20-alpine AS base
RUN corepack enable
FROM base AS deps
WORKDIR /app
COPY package.json pnpm-lock.yaml ./
RUN pnpm install --frozen-lockfile
FROM base AS build
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN pnpm build
FROM base AS runtime
WORKDIR /app
COPY --from=build /app/.output ./.output
ENV NODE_ENV=production
ENV NUXT_HOST=0.0.0.0
ENV NUXT_PORT=3000
EXPOSE 3000
USER node
CMD ["node", ".output/server/index.mjs"]
# docker-compose.yml
services:
app:
build: .
ports:
- "3000:3000"
env_file: .env.production
restart: unless-stopped
healthcheck:
test: ["CMD", "wget", "-qO-", "http://localhost:3000/api/health"]
interval: 30s
timeout: 5s
retries: 3
3. Deploy to Vercel
# Install Vercel CLI
npm i -g vercel
# Deploy
vercel --prod
// vercel.json
{
"buildCommand": "nuxt build",
"outputDirectory": ".output",
"framework": "nuxtjs"
}
4. Cloudflare Pages
// nuxt.config.ts
export default defineNuxtConfig({
nitro: {
preset: 'cloudflare-pages',
},
})
# Deploy via Wrangler
npx wrangler pages deploy .output/public
5. Environment Variables
// nuxt.config.ts
export default defineNuxtConfig({
runtimeConfig: {
// Server-only (NUXT_ prefix)
databaseUrl: process.env.NUXT_DATABASE_URL,
jwtSecret: process.env.NUXT_JWT_SECRET,
// Public (NUXT_PUBLIC_ prefix)
public: {
apiBase: process.env.NUXT_PUBLIC_API_BASE || '/api',
appName: 'My App',
},
},
})
# .env.production
NUXT_DATABASE_URL=postgresql://user:pass@host:5432/db
NUXT_JWT_SECRET=super-secret-key
NUXT_PUBLIC_API_BASE=https://api.example.com
6. GitHub Actions CI/CD
# .github/workflows/deploy.yml
name: Deploy
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: 9
- uses: actions/setup-node@v4
with:
node-version: 20
cache: pnpm
- run: pnpm install --frozen-lockfile
- run: pnpm test
env:
NUXT_PUBLIC_API_BASE: http://localhost:3000
- run: pnpm build
- name: Deploy to server
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SSH_KEY }}
script: |
cd /app
docker compose pull
docker compose up -d --build
7. PM2 Production
// ecosystem.config.cjs
module.exports = {
apps: [{
name: 'nuxt-app',
script: '.output/server/index.mjs',
instances: 'max',
exec_mode: 'cluster',
env_production: {
NODE_ENV: 'production',
NUXT_PORT: 3000,
},
}],
}
pm2 start ecosystem.config.cjs --env production
pm2 save
pm2 startup
Next article: Production Monitoring & Best Practices — Sentry, logging, security.