Skip to main content
AI / Machine Learning

Phase 9: QA, Publishing & Capstone

10 Modules
Chapter 4: Hands-On: Deploy to Production40%

Hands-On: Deploy to Production

Duration: 90 minutes Difficulty: 🟡 Intermediate

Overview

In this hands-on session, you'll deploy three types of projects to production:

  1. A React application to Vercel
  2. A Node.js API to Railway
  3. A documentation site with MkDocs Material

By the end, you'll have live URLs for all three projects with automated CI/CD pipelines.


Exercise 1: Deploy React App to Vercel (30 minutes)

Step 1: Prepare Your React Application

Create a simple React app or use an existing one:

# Create new React app with Vite
npm create vite@latest my-app -- --template react
cd my-app
npm install

Add a production build script to package.json:

{
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview"
  }
}

Test the build locally:

npm run build
npm run preview

Step 2: Push to GitHub

# Initialize Git
git init
git add .
git commit -m "Initial commit"

# Create GitHub repository and push
gh repo create my-app --public --source=. --remote=origin --push
# Or manually create on GitHub and:
git remote add origin https://github.com/YOUR_USERNAME/my-app.git
git push -u origin main

Step 3: Deploy to Vercel

Option A: Using Vercel Dashboard (Recommended for beginners)

  1. Visit vercel.com
  2. Sign up/log in with GitHub
  3. Click "Add New... → Project"
  4. Import your GitHub repository
  5. Configure build settings:
    • Framework Preset: Vite
    • Root Directory: ./
    • Build Command: npm run build
    • Output Directory: dist
  6. Click "Deploy"

Option B: Using Vercel CLI (Faster for repeat deployments)

# Install Vercel CLI
npm i -g vercel

# Deploy
vercel

# Follow prompts:
# Set up and deploy? Yes
# Which scope? (select your account)
# Link to existing project? No
# Project name? (accept default)
# Directory? (press Enter for current)
# Want to override settings? No

# Production deployment
vercel --prod

Step 4: Verify Deployment

Your app is now live! You'll get two URLs:

  • Preview URL: my-app-abc123.vercel.app (for this specific deployment)
  • Production URL: my-app.vercel.app (always points to latest production)

Visit the URL and verify your app works.

Step 5: Add Custom Domain (Optional)

In Vercel Dashboard:

  1. Project Settings → Domains
  2. Add your domain (e.g., myapp.com)
  3. Configure DNS records as instructed
  4. Vercel automatically provisions SSL certificate

Exercise 2: Deploy Node.js API to Railway (30 minutes)

Step 1: Create Express API

mkdir my-api
cd my-api
npm init -y
npm install express cors dotenv

Create server.js:

// server.js
import express from 'express';
import cors from 'cors';
import 'dotenv/config';

const app = express();
const PORT = process.env.PORT || 3000;

app.use(cors());
app.use(express.json());

// Health check endpoint
app.get('/health', (req, res) => {
  res.json({ status: 'healthy', timestamp: new Date().toISOString() });
});

// Sample API endpoint
app.get('/api/tasks', (req, res) => {
  res.json([
    { id: 1, title: 'Deploy to Railway', completed: true },
    { id: 2, title: 'Configure environment variables', completed: false }
  ]);
});

app.post('/api/tasks', (req, res) => {
  const { title } = req.body;
  res.status(201).json({ id: Date.now(), title, completed: false });
});

app.listen(PORT, () => {
  console.log(`API running on port ${PORT}`);
});

Update package.json:

{
  "type": "module",
  "scripts": {
    "start": "node server.js",
    "dev": "node --watch server.js"
  }
}

Test locally:

npm run dev
# Visit http://localhost:3000/health

Step 2: Push to GitHub

git init
echo "node_modules\n.env" > .gitignore
git add .
git commit -m "Initial API commit"
gh repo create my-api --public --source=. --remote=origin --push

Step 3: Deploy to Railway

Option A: Using Railway Dashboard

  1. Visit railway.app
  2. Sign up with GitHub
  3. Click "New Project"
  4. Select "Deploy from GitHub repo"
  5. Choose your my-api repository
  6. Railway auto-detects Node.js and deploys

Option B: Using Railway CLI

# Install Railway CLI
npm i -g @railway/cli

# Login
railway login

# Initialize project
railway init

# Link to GitHub repo (optional)
railway link

# Deploy
railway up

Step 4: Configure Environment Variables

In Railway Dashboard:

  1. Select your service
  2. Go to "Variables" tab
  3. Add variables:
    • NODE_ENV: production
    • API_KEY: your-secret-key

Or via CLI:

railway variables set NODE_ENV=production
railway variables set API_KEY=your-secret-key

Step 5: Get Your API URL

Railway generates a URL like: https://my-api-production.up.railway.app

Test your API:

curl https://my-api-production.up.railway.app/health

Step 6: Add PostgreSQL Database (Optional)

In Railway Dashboard:

  1. Click "New" → "Database" → "PostgreSQL"
  2. Railway automatically sets DATABASE_URL environment variable
  3. Access in your code:
import pg from 'pg';

const pool = new pg.Pool({
  connectionString: process.env.DATABASE_URL,
  ssl: { rejectUnauthorized: false }
});

app.get('/api/tasks', async (req, res) => {
  const result = await pool.query('SELECT * FROM tasks');
  res.json(result.rows);
});

Exercise 3: Deploy Documentation with MkDocs Material (30 minutes)

Step 1: Install MkDocs Material

pip install mkdocs-material
# Or with pipx for isolation
pipx install mkdocs-material

Step 2: Create Documentation Site

mkdir my-docs
cd my-docs
mkdocs new .

This creates:

my-docs/
├── mkdocs.yml      # Configuration
└── docs/
    └── index.md    # Homepage

Step 3: Configure Material Theme

Edit mkdocs.yml:

site_name: My Project Documentation
site_url: https://my-docs.example.com
repo_url: https://github.com/username/my-docs

theme:
  name: material
  palette:
    # Light mode
    - scheme: default
      primary: indigo
      accent: indigo
      toggle:
        icon: material/brightness-7
        name: Switch to dark mode
    # Dark mode
    - scheme: slate
      primary: indigo
      accent: indigo
      toggle:
        icon: material/brightness-4
        name: Switch to light mode
  features:
    - navigation.tabs
    - navigation.sections
    - navigation.expand
    - navigation.top
    - search.suggest
    - search.highlight
    - content.code.copy
    - content.code.annotate

plugins:
  - search

markdown_extensions:
  - pymdownx.highlight:
      anchor_linenums: true
      line_spans: __span
      pygments_lang_class: true
  - pymdownx.superfences:
      custom_fences:
        - name: mermaid
          class: mermaid
          format: !!python/name:pymdownx.superfences.fence_code_format
  - pymdownx.tabbed:
      alternate_style: true
  - admonition
  - pymdownx.details
  - attr_list
  - md_in_html

nav:
  - Home: index.md
  - Getting Started:
    - Installation: getting-started/installation.md
    - Quick Start: getting-started/quickstart.md
  - API Reference:
    - Overview: api/overview.md
    - Endpoints: api/endpoints.md

Step 4: Add Documentation Pages

Create docs/getting-started/installation.md:

# Installation

## Prerequisites

- Node.js 20 or higher
- npm or yarn package manager

## Install via npm

\`\`\`bash
npm install my-package
\`\`\`

## Install via yarn

\`\`\`bash
yarn add my-package
\`\`\`

!!! warning "Python 3.10+"
    This package requires Python 3.10 or higher for CLI tools.

Test locally:

mkdocs serve
# Visit http://localhost:8000

Step 5: Deploy to GitHub Pages

# Push to GitHub first
git init
git add .
git commit -m "Initial docs"
gh repo create my-docs --public --source=. --remote=origin --push

# Deploy to GitHub Pages
mkdocs gh-deploy

Your docs are now live at: https://username.github.io/my-docs/

Step 6: Alternative - Deploy to Vercel

# Build static site
mkdocs build

# Deploy to Vercel
vercel deploy

In Vercel, configure:

  • Build Command: pip install mkdocs-material && mkdocs build
  • Output Directory: site

Bonus Exercise: GitHub Actions Automation (20 minutes)

Set up automatic deployments on every push.

For Vercel (React App)

Create .github/workflows/deploy.yml:

name: Deploy to Vercel

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Build
        run: npm run build

      - name: Deploy to Vercel
        uses: amondnet/vercel-action@v25
        with:
          vercel-token: ${{ secrets.VERCEL_TOKEN }}
          vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
          vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
          vercel-args: '--prod'

For Railway (API)

Create .github/workflows/deploy-api.yml:

name: Deploy API to Railway

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Install Railway CLI
        run: npm i -g @railway/cli

      - name: Deploy to Railway
        run: railway up --service=my-api
        env:
          RAILWAY_TOKEN: ${{ secrets.RAILWAY_TOKEN }}

For MkDocs (Documentation)

Create .github/workflows/docs.yml:

name: Deploy Documentation

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup Python
        uses: actions/setup-python@v5
        with:
          python-version: 3.x

      - name: Install MkDocs
        run: pip install mkdocs-material

      - name: Deploy to GitHub Pages
        run: mkdocs gh-deploy --force

Troubleshooting Common Issues

Vercel Build Fails

Problem: Error: Command "npm run build" exited with 1

Solutions:

  1. Check package.json has correct build script
  2. Verify all dependencies are in dependencies (not devDependencies)
  3. Set Node.js version: Create vercel.json:
    {
      "buildCommand": "npm run build",
      "devCommand": "npm run dev",
      "framework": "vite",
      "installCommand": "npm install",
      "outputDirectory": "dist"
    }
    

Railway Port Issues

Problem: Service starts but shows "Application failed to respond"

Solution: Railway provides PORT environment variable. Use it:

const PORT = process.env.PORT || 3000;

MkDocs GitHub Pages 404

Problem: Documentation deploys but shows 404

Solutions:

  1. Check GitHub Pages is enabled: Settings → Pages → Source: gh-pages branch
  2. Verify site_url in mkdocs.yml matches GitHub Pages URL
  3. Wait 2-3 minutes for DNS propagation

Environment Variables Not Working

Problem: Secrets not accessible in application

Solutions:

  1. Restart service after adding variables
  2. Check variable names match exactly (case-sensitive)
  3. For preview deployments, ensure variables are set for "Preview" environment

Verification Checklist

After completing all exercises, verify:

  • React app accessible at Vercel URL
  • API health check endpoint responds
  • Documentation site loads with correct theme
  • All sites use HTTPS automatically
  • Environment variables configured correctly
  • GitHub Actions workflows (if configured) passing

Next Steps

Now that you have live deployments, you'll learn to:

  • Set up preview deployments for PRs
  • Configure custom domains
  • Add monitoring and error tracking
  • Implement zero-downtime deployments

Next: 03_exercises.md - Advanced Deployment Patterns


Quick Reference Commands

# Vercel
vercel                    # Deploy preview
vercel --prod            # Deploy production
vercel logs              # View logs
vercel env ls            # List environment variables

# Railway
railway up               # Deploy
railway logs             # View logs
railway open             # Open in browser
railway variables        # Manage environment variables

# MkDocs
mkdocs serve            # Local preview
mkdocs build            # Build static site
mkdocs gh-deploy        # Deploy to GitHub Pages