Skip to content

Deploy Frontend ​

This guide covers deploying the React frontend to production.

Quick Deploy to Vercel ​

Vercel is the easiest platform for deploying React applications, created by the makers of Next.js.

1. Prerequisites ​

  • GitHub account
  • Vercel account (vercel.com)
  • Code pushed to GitHub repository
  • Backend deployed and accessible

2. Import Project ​

  1. Go to vercel.com/new
  2. Click "Import Project"
  3. Select your GitHub repository
  4. Vercel auto-detects Vite configuration

3. Configure Project ​

  • Framework Preset: Vite
  • Root Directory: frontend (if in subdirectory)
  • Build Command: npm run build
  • Output Directory: dist
  • Install Command: npm install

4. Add Environment Variables ​

In project settings, add:

bash
VITE_API_URL=https://your-backend.railway.app
VITE_SUPABASE_URL=https://YOUR_PROJECT.supabase.co
VITE_SUPABASE_ANON_KEY=your_anon_key

Important: All Vite env vars must start with VITE_

5. Deploy ​

Click "Deploy". Vercel builds and deploys automatically.

Your site will be live at:

https://acodeaday.vercel.app

6. Configure Custom Domain (Optional) ​

  1. Go to project Settings > Domains
  2. Add your custom domain
  3. Follow DNS configuration instructions
  4. Vercel automatically provisions SSL certificate

7. Update Backend CORS ​

Add your Vercel URL to backend CORS:

python
# backend/app/main.py
app.add_middleware(
    CORSMiddleware,
    allow_origins=[
        "https://acodeaday.vercel.app",
        "https://yourdomain.com"
    ],
    ...
)

Redeploy backend.

Deploy to Netlify ​

Netlify is another excellent platform with generous free tier.

1. Connect Repository ​

  1. Go to app.netlify.com
  2. Click "Add new site" > "Import an existing project"
  3. Connect to GitHub and select repository

2. Configure Build Settings ​

  • Base directory: frontend
  • Build command: npm run build
  • Publish directory: frontend/dist

3. Add Environment Variables ​

In Site settings > Build & deploy > Environment:

bash
VITE_API_URL=https://your-backend.railway.app
VITE_SUPABASE_URL=https://YOUR_PROJECT.supabase.co
VITE_SUPABASE_ANON_KEY=your_anon_key

4. Deploy ​

Click "Deploy site". Netlify builds and deploys.

Your site will be at:

https://acodeaday.netlify.app

5. Configure Redirects ​

Create frontend/public/_redirects:

/*    /index.html   200

This enables client-side routing for TanStack Router.

6. Custom Domain ​

  1. Go to Site settings > Domain management
  2. Add custom domain
  3. Configure DNS
  4. SSL is automatic

Deploy to Cloudflare Pages ​

Cloudflare Pages offers excellent performance with global CDN.

1. Connect Repository ​

  1. Go to dash.cloudflare.com/pages
  2. Click "Create a project"
  3. Connect GitHub repository

2. Configure Build ​

  • Production branch: main
  • Framework preset: Vite
  • Build command: npm run build
  • Build output directory: dist
  • Root directory: frontend

3. Add Environment Variables ​

bash
VITE_API_URL=https://your-backend.railway.app
VITE_SUPABASE_URL=https://YOUR_PROJECT.supabase.co
VITE_SUPABASE_ANON_KEY=your_anon_key
NODE_VERSION=22

4. Deploy ​

Click "Save and Deploy". Site will be at:

https://acodeaday.pages.dev

5. Configure Redirects ​

Create frontend/public/_redirects:

/*    /index.html   200

Deploy to AWS S3 + CloudFront ​

For full control and AWS integration.

1. Build Locally ​

bash
cd frontend
npm run build

2. Create S3 Bucket ​

bash
aws s3 mb s3://acodeaday-frontend
aws s3 website s3://acodeaday-frontend --index-document index.html

3. Upload Build ​

bash
aws s3 sync dist/ s3://acodeaday-frontend --delete

4. Configure Bucket Policy ​

json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "PublicReadGetObject",
      "Effect": "Allow",
      "Principal": "*",
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::acodeaday-frontend/*"
    }
  ]
}

5. Create CloudFront Distribution ​

  1. Go to CloudFront console
  2. Create distribution
  3. Origin: Your S3 bucket
  4. Default root object: index.html
  5. Error pages: 404 → /index.html (for client-side routing)

6. Deploy Updates ​

bash
npm run build
aws s3 sync dist/ s3://acodeaday-frontend --delete
aws cloudfront create-invalidation --distribution-id YOUR_ID --paths "/*"

Environment Variables Per Environment ​

Development ​

bash
# frontend/.env.development
VITE_API_URL=http://localhost:8000
VITE_SUPABASE_URL=http://localhost:54321
VITE_SUPABASE_ANON_KEY=local_key

Staging ​

bash
# frontend/.env.staging
VITE_API_URL=https://staging-api.yourapp.com
VITE_SUPABASE_URL=https://staging.supabase.co
VITE_SUPABASE_ANON_KEY=staging_key

Production ​

bash
# frontend/.env.production
VITE_API_URL=https://api.yourapp.com
VITE_SUPABASE_URL=https://prod.supabase.co
VITE_SUPABASE_ANON_KEY=prod_key

Vite automatically uses the correct .env file based on build mode.

Optimization ​

Enable Compression ​

Most platforms (Vercel, Netlify, Cloudflare) enable Gzip/Brotli automatically.

Code Splitting ​

Vite automatically code-splits by route. Verify in build output:

bash
npm run build

# Output shows chunk sizes:
# dist/assets/index-a1b2c3.js    142.50 kB
# dist/assets/Problem-x7y8z9.js   45.20 kB

Preload Critical Assets ​

In index.html:

html
<link rel="preload" href="/fonts/inter.woff2" as="font" type="font/woff2" crossorigin>

Analyze Bundle Size ​

bash
npm install -D rollup-plugin-visualizer

Update vite.config.ts:

typescript
import { visualizer } from 'rollup-plugin-visualizer';

export default defineConfig({
  plugins: [
    react(),
    visualizer({ open: true })
  ]
});

Run npm run build to see bundle analysis.

Performance Best Practices ​

1. Enable Caching ​

Vite automatically adds content hashes to filenames for long-term caching.

2. Lazy Load Routes ​

TanStack Router supports code splitting:

typescript
// routes/problem.$slug.tsx
export const Route = createFileRoute('/problem/$slug')({
  component: lazy(() => import('@/components/ProblemView'))
})

3. Optimize Images ​

  • Use modern formats (WebP, AVIF)
  • Compress images
  • Use loading="lazy" attribute

4. Minimize Dependencies ​

Review and remove unused packages:

bash
npx depcheck

Monitoring ​

Add Analytics ​

Vercel Analytics:

bash
npm install @vercel/analytics
typescript
import { Analytics } from '@vercel/analytics/react'

function App() {
  return (
    <>
      <YourApp />
      <Analytics />
    </>
  )
}

Google Analytics:

bash
npm install react-ga4

Error Tracking ​

Sentry:

bash
npm install @sentry/react
typescript
import * as Sentry from "@sentry/react";

Sentry.init({
  dsn: "your-sentry-dsn",
  environment: "production",
  integrations: [new Sentry.BrowserTracing()],
  tracesSampleRate: 1.0,
});

Security Headers ​

Vercel ​

Create vercel.json:

json
{
  "headers": [
    {
      "source": "/(.*)",
      "headers": [
        {
          "key": "X-Content-Type-Options",
          "value": "nosniff"
        },
        {
          "key": "X-Frame-Options",
          "value": "DENY"
        },
        {
          "key": "X-XSS-Protection",
          "value": "1; mode=block"
        }
      ]
    }
  ]
}

Netlify ​

Create netlify.toml:

toml
[[headers]]
  for = "/*"
  [headers.values]
    X-Frame-Options = "DENY"
    X-XSS-Protection = "1; mode=block"
    X-Content-Type-Options = "nosniff"

CI/CD ​

Automatic Deploys ​

Vercel, Netlify, and Cloudflare Pages automatically deploy on Git push:

  • main branch → Production
  • develop branch → Preview (optional)
  • Pull requests → Preview deployments

Preview Deployments ​

Every PR gets a unique preview URL:

https://acodeaday-pr-123.vercel.app

Perfect for testing before merge!

Troubleshooting ​

Blank page after deploy ​

  • Check browser console for errors
  • Verify environment variables are set
  • Check API URL is accessible
  • Ensure CORS allows your frontend domain

404 on page refresh ​

Add redirect rule:

/*    /index.html   200

Environment variables not working ​

  • Verify they start with VITE_
  • Rebuild after adding env vars
  • Check they're set in platform dashboard

Build fails ​

bash
# Check build locally
npm run build

# Check Node.js version matches
node --version  # Should be 22+

Next Steps ​