Skip to content

Deployment Guide ​

Learn how to deploy your CurisJS application to various platforms.

Overview ​

CurisJS applications can be deployed to any platform that supports Node.js, Bun, Deno, or edge runtimes. This guide covers the most popular deployment options.

Build for Production ​

Before deploying, build your application:

bash
# Using the CLI
curis build

# Or manually with your package manager
pnpm run build

This creates an optimized production build in the dist/ directory.

Node.js Deployment ​

Traditional Server ​

Deploy to any VPS or cloud server with Node.js:

1. Prepare your server:

bash
# Install Node.js 18+
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt-get install -y nodejs

# Install process manager
npm install -g pm2

2. Deploy your application:

bash
# Upload your files
scp -r dist package.json your-server:/app/

# Install dependencies on server
ssh your-server "cd /app && npm install --production"

# Start with PM2
ssh your-server "cd /app && pm2 start dist/index.js --name curis-app"

3. Configure PM2 ecosystem:

javascript
// ecosystem.config.js
module.exports = {
  apps: [{
    name: 'curis-app',
    script: './dist/index.js',
    instances: 'max',
    exec_mode: 'cluster',
    env: {
      NODE_ENV: 'production',
      PORT: 3000,
    },
  }],
};

Docker ​

Dockerfile:

dockerfile
FROM node:20-alpine AS base

# Dependencies
FROM base AS deps
WORKDIR /app
COPY package.json pnpm-lock.yaml ./
RUN npm install -g pnpm && pnpm install --frozen-lockfile --production

# Builder
FROM base AS builder
WORKDIR /app
COPY package.json pnpm-lock.yaml ./
RUN npm install -g pnpm && pnpm install --frozen-lockfile
COPY . .
RUN pnpm run build

# Runner
FROM base AS runner
WORKDIR /app

ENV NODE_ENV=production
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 curisjs

COPY --from=deps --chown=curisjs:nodejs /app/node_modules ./node_modules
COPY --from=builder --chown=curisjs:nodejs /app/dist ./dist
COPY --from=builder --chown=curisjs:nodejs /app/package.json ./

USER curisjs
EXPOSE 3000
ENV PORT=3000

CMD ["node", "dist/index.js"]

docker-compose.yml:

yaml
version: '3.8'

services:
  app:
    build: .
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=production
      - DATABASE_URL=postgresql://user:pass@db:5432/myapp
    depends_on:
      - db
    restart: unless-stopped
  
  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: pass
      POSTGRES_DB: myapp
    volumes:
      - postgres_data:/var/lib/postgresql/data
    restart: unless-stopped

volumes:
  postgres_data:

Deploy:

bash
docker-compose up -d

Platform-Specific Guides ​

Vercel ​

1. Install Vercel CLI:

bash
npm install -g vercel

2. Create vercel.json:

json
{
  "buildCommand": "pnpm run build",
  "outputDirectory": "dist",
  "installCommand": "pnpm install",
  "framework": null,
  "rewrites": [
    { "source": "/(.*)", "destination": "/api" }
  ]
}

3. Deploy:

bash
vercel --prod

Railway ​

1. Create railway.json:

json
{
  "build": {
    "builder": "nixpacks"
  },
  "deploy": {
    "startCommand": "node dist/index.js",
    "restartPolicyType": "on-failure",
    "restartPolicyMaxRetries": 10
  }
}

2. Deploy:

bash
# Install Railway CLI
npm install -g @railway/cli

# Login and deploy
railway login
railway init
railway up

Render ​

1. Create render.yaml:

yaml
services:
  - type: web
    name: curis-app
    env: node
    buildCommand: pnpm install && pnpm run build
    startCommand: node dist/index.js
    envVars:
      - key: NODE_ENV
        value: production

2. Connect your repository to Render:

  • Go to Render Dashboard
  • Create new Web Service
  • Connect your Git repository
  • Render will auto-deploy on push

Fly.io ​

1. Install Fly CLI:

bash
curl -L https://fly.io/install.sh | sh

2. Create fly.toml:

toml
app = "curis-app"
primary_region = "sjc"

[build]
  builder = "heroku/buildpacks:20"

[[services]]
  internal_port = 3000
  protocol = "tcp"

  [[services.ports]]
    handlers = ["http"]
    port = 80

  [[services.ports]]
    handlers = ["tls", "http"]
    port = 443

3. Deploy:

bash
fly launch
fly deploy

AWS (Elastic Beanstalk) ​

1. Install EB CLI:

bash
pip install awsebcli

2. Initialize:

bash
eb init -p node.js-18 curis-app

3. Create .ebextensions/nodecommand.config:

yaml
option_settings:
  aws:elasticbeanstalk:container:nodejs:
    NodeCommand: "node dist/index.js"

4. Deploy:

bash
eb create production
eb deploy

Google Cloud Run ​

1. Build container:

bash
gcloud builds submit --tag gcr.io/PROJECT_ID/curis-app

2. Deploy:

bash
gcloud run deploy curis-app \
  --image gcr.io/PROJECT_ID/curis-app \
  --platform managed \
  --region us-central1 \
  --allow-unauthenticated

Azure Container Apps ​

1. Build and push:

bash
az acr build --registry myregistry --image curis-app:latest .

2. Deploy:

bash
az containerapp create \
  --name curis-app \
  --resource-group myResourceGroup \
  --image myregistry.azurecr.io/curis-app:latest \
  --target-port 3000 \
  --ingress external

Edge Runtime Deployment ​

Cloudflare Workers ​

wrangler.toml:

toml
name = "curis-app"
main = "src/index.ts"
compatibility_date = "2024-11-17"

[build]
command = "pnpm run build"

Deploy:

bash
npx wrangler deploy

Deno Deploy ​

deno.json:

json
{
  "tasks": {
    "start": "deno run --allow-net --allow-env src/index.ts"
  },
  "imports": {
    "@curisjs/core": "npm:@curisjs/core"
  }
}

Deploy:

bash
deployctl deploy --project=curis-app src/index.ts

Environment Variables ​

Set environment variables on your platform:

bash
# Railway
railway variables set DATABASE_URL=postgres://...

# Vercel
vercel env add DATABASE_URL

# Render (in dashboard)
# Fly.io
fly secrets set DATABASE_URL=postgres://...

# AWS EB
eb setenv DATABASE_URL=postgres://...

Database Setup ​

PostgreSQL on Render ​

bash
# Create database
render databases create my-postgres

# Get connection string
render databases url my-postgres

PostgreSQL on Railway ​

bash
# Add PostgreSQL plugin
railway add postgres

# Connection string is auto-injected as DATABASE_URL

Health Checks ​

Add a health check endpoint:

typescript
app.get('/health', (ctx) => {
  return ctx.json({ status: 'ok', timestamp: Date.now() });
});

Configure on your platform:

yaml
# docker-compose.yml
healthcheck:
  test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
  interval: 30s
  timeout: 3s
  retries: 3

Monitoring ​

Logging ​

Use structured logging:

typescript
import { Logger } from '@curisjs/core';

const logger = new Logger();
logger.info('Server started', { port: 3000 });

Error Tracking ​

Integrate error tracking:

typescript
import * as Sentry from '@sentry/node';

Sentry.init({
  dsn: process.env.SENTRY_DSN,
  environment: process.env.NODE_ENV,
});

app.use(async (ctx, next) => {
  try {
    await next();
  } catch (error) {
    Sentry.captureException(error);
    throw error;
  }
});

Performance Tips ​

  1. Enable compression:
typescript
import { compression } from '@curisjs/core/middleware';
app.use(compression());
  1. Set production environment:
bash
export NODE_ENV=production
  1. Use process clustering:
javascript
// ecosystem.config.js
{
  instances: 'max',
  exec_mode: 'cluster'
}
  1. Configure caching:
typescript
ctx.setHeader('Cache-Control', 'public, max-age=3600');
  1. Enable HTTP/2:
typescript
import { createSecureServer } from 'node:http2';
import { nodeAdapter } from '@curisjs/core/adapters';

const server = createSecureServer({
  key: readFileSync('key.pem'),
  cert: readFileSync('cert.pem'),
}, nodeAdapter(app));

Troubleshooting ​

Port Issues ​

Make sure to use the PORT environment variable:

typescript
const port = parseInt(process.env.PORT || '3000');
app.listen({ port });

Build Failures ​

Check build logs:

bash
# Railway
railway logs

# Vercel
vercel logs

# Render (in dashboard)

Database Connections ​

Test database connectivity:

bash
# PostgreSQL
psql $DATABASE_URL -c "SELECT 1"

# MySQL
mysql -h host -u user -p

Next Steps ​

Released under the MIT License.