> ## Documentation Index
> Fetch the complete documentation index at: https://docs.markup.freddiephilpot.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Deployment

> Deploy Markup to production using Vercel, Docker, or a custom server.

# Deployment

Markup can be deployed as a standard Next.js application using platforms such as:

* Vercel
* Docker
* VPS / Dedicated Servers
* Railway
* Coolify
* Render

The application requires:

* PostgreSQL database
* Environment variables configured
* Prisma migrations applied

***

# Production Requirements

Before deployment, ensure you have:

* Node.js 18+
* PostgreSQL database
* WorkOS application configured
* Production environment variables configured
* HTTPS enabled for authentication callbacks

***

# Required Environment Variables

Example production configuration:

```dotenv theme={null}
DATABASE_URL=postgresql://user:password@host:5432/markup?sslmode=require

WORKOS_CLIENT_ID=client_xxxxx
WORKOS_API_KEY=sk_live_xxxxx
WORKOS_COOKIE_PASSWORD=secure_random_string

NEXT_PUBLIC_WORKOS_REDIRECT_URI=https://yourdomain.com/api/auth/callback

NEXT_PUBLIC_DB_PROVIDER=postgres/convex
```

***

# Build the Application

Install dependencies:

```bash theme={null}
npm install
```

Generate the Prisma client:

```bash theme={null}
npx prisma generate
```

Build the production application:

```bash theme={null}
npm run build
```

Start the production server:

```bash theme={null}
npm run start
```

***

# Database Migrations

Run Prisma migrations before starting production deployments:

```bash theme={null}
npx prisma migrate deploy
```

This applies all pending migrations safely in production.

***

# Deploying to Vercel

## 1. Push Repository to GitHub

Ensure your repository is committed and pushed.

***

## 2. Import Project into Vercel

1. Open the Vercel dashboard
2. Import the GitHub repository
3. Select the project
4. Configure environment variables

***

## 3. Configure Environment Variables

Add all required variables from `.env.local` into:

```txt theme={null}
Vercel Project Settings → Environment Variables
```

***

## 4. Configure PostgreSQL

You can use:

* Neon
* Supabase
* Railway PostgreSQL
* Vercel Postgres
* Self-hosted PostgreSQL

Ensure SSL is enabled if required by the provider.

***

## 5. Deploy

Vercel automatically runs:

```bash theme={null}
npm run build
```

After deployment, run migrations:

```bash theme={null}
npx prisma migrate deploy
```

***

# Deploying with Docker

## Docker Compose

```docker theme={null}
services:
  db:
    image: postgres:16-alpine
    restart: unless-stopped
    environment:
      POSTGRES_USER: markup
      POSTGRES_PASSWORD: markup_password
      POSTGRES_DB: markup
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U markup -d markup"]
      interval: 10s
      timeout: 5s
      retries: 5

  app:
    build:
      context: .
      dockerfile: Dockerfile
      args:
        NEXT_PUBLIC_DB_PROVIDER: postgres
    restart: unless-stopped
    depends_on:
      db:
        condition: service_healthy
    ports:
      - "3001:3000"
    environment:
      # Database — points to the postgres service above
      DATABASE_URL: postgresql://markup:markup_password@db:5432/markup

      # WorkOS auth — fill these in or use a .env file
      WORKOS_CLIENT_ID: ${WORKOS_CLIENT_ID}
      WORKOS_API_KEY: ${WORKOS_API_KEY}
      WORKOS_COOKIE_PASSWORD: ${WORKOS_COOKIE_PASSWORD}
      NEXT_PUBLIC_WORKOS_REDIRECT_URI: ${NEXT_PUBLIC_WORKOS_REDIRECT_URI}

      # App URL (used for CSP / redirect base)
      NEXT_PUBLIC_SITE_URL: ${NEXT_PUBLIC_SITE_URL:-http://localhost:3000}

      # Use Postgres instead of Convex for self-hosted deployments
      NEXT_PUBLIC_DB_PROVIDER: postgres

      NODE_ENV: production

volumes:
  postgres_data:
```

## Dockerfile

```docker theme={null}
FROM node:20-alpine AS base

# Install dependencies only when needed
FROM base AS deps
RUN apk add --no-cache libc6-compat openssl
WORKDIR /app

COPY package.json package-lock.json ./
RUN npm ci --ignore-scripts --legacy-peer-deps

# Rebuild the source code only when needed
FROM base AS builder
RUN apk add --no-cache openssl
WORKDIR /app

COPY --from=deps /app/node_modules ./node_modules
COPY . .

# Accept public env vars as build args so Next.js can bake them into the bundle
ARG NEXT_PUBLIC_DB_PROVIDER=postgres
ENV NEXT_PUBLIC_DB_PROVIDER=$NEXT_PUBLIC_DB_PROVIDER

# Generate Prisma client (dummy DATABASE_URL satisfies schema validation at build time)
RUN DATABASE_URL="postgresql://dummy:dummy@localhost:5432/dummy" node node_modules/prisma/build/index.js generate

# Build the Next.js app (no Convex deploy, just the Next build)
RUN npm run build:docker

# Production image
FROM base AS runner
RUN apk add --no-cache openssl
WORKDIR /app

ENV NODE_ENV=production

RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs

COPY --from=builder /app/public ./public

# Leverage Next.js standalone output
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static

# Copy Prisma schema and migrations so we can run migrations at startup
COPY --from=builder /app/prisma ./prisma
COPY --from=builder /app/node_modules/.prisma ./node_modules/.prisma
COPY --from=builder /app/node_modules/@prisma ./node_modules/@prisma
COPY --from=builder /app/node_modules/prisma ./node_modules/prisma

COPY docker-entrypoint.sh ./docker-entrypoint.sh
RUN chmod +x ./docker-entrypoint.sh

USER nextjs

EXPOSE 3000

ENV PORT=3000
ENV HOSTNAME="0.0.0.0"

ENTRYPOINT ["./docker-entrypoint.sh"]
```

# Deploying on a VPS

## Clone the Repository

```bash theme={null}
git clone https://github.com/pphilfre/markup.git
cd markup
```

***

## Install Dependencies

```bash theme={null}
npm install
```

***

## Configure Environment Variables

Create:

```txt theme={null}
.env.production
```

Add all required production variables.

***

## Generate Prisma Client

```bash theme={null}
npx prisma generate
```

***

## Run Migrations

```bash theme={null}
npx prisma migrate deploy
```

***

## Build Application

```bash theme={null}
npm run build
```

***

## Start Server

```bash theme={null}
npm run start
```

***

# Reverse Proxy Example (Nginx)

```nginx theme={null}
server {
    listen 80;
    server_name yourdomain.com;

    location / {
        proxy_pass http://localhost:3000;

        proxy_http_version 1.1;

        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';

        proxy_set_header Host $host;

        proxy_cache_bypass $http_upgrade;
    }
}
```

***

# Recommended Production Setup

Recommended stack:

* Next.js application
* PostgreSQL database
* Nginx reverse proxy
* HTTPS via Let's Encrypt
* PM2 or Docker for process management

***

# PM2 Example

Install PM2:

```bash theme={null}
npm install -g pm2
```

Start the application:

```bash theme={null}
pm2 start npm --name markup -- run start
```

Save PM2 configuration:

```bash theme={null}
pm2 save
```

Enable startup:

```bash theme={null}
pm2 startup
```

***

# Updating Production Deployments

Pull latest changes:

```bash theme={null}
git pull
```

Install dependencies:

```bash theme={null}
npm install
```

Run migrations:

```bash theme={null}
npx prisma migrate deploy
```

Rebuild application:

```bash theme={null}
npm run build
```

Restart application:

```bash theme={null}
pm2 restart markup
```

***

# Security Recommendations

* Use HTTPS in production
* Enable PostgreSQL SSL
* Restrict database access
* Never expose `.env` files publicly
* Use strong secrets
* Rotate API keys periodically
* Enable automatic backups

***

# Troubleshooting

## Prisma Migration Failures

Check migration status:

```bash theme={null}
npx prisma migrate status
```

***

## Application Fails to Start

Verify:

* Environment variables exist
* Database is reachable
* Prisma client is generated
* Build completed successfully

***

## WorkOS Authentication Errors

Ensure:

* Redirect URI matches production domain
* HTTPS is enabled
* Callback URLs are configured in WorkOS

***

# Deployment Checklist

1. Environment variables configured
2. PostgreSQL database running
3. Prisma migrations applied
4. HTTPS enabled
5. WorkOS redirect URI configured
6. Application successfully built
7. Backups configured
8. Monitoring/logging enabled
