Overview
After building your portfolio, you can deploy it to various hosting platforms. This guide covers the most popular options for hosting static React applications.
Environment Variables
Your portfolio uses EmailJS for the contact form, which requires three environment variables:
VITE_SEVICE_ID = your_emailjs_service_id
VITE_TEMPLATE_ID = your_emailjs_template_id
VITE_PUBLIC_KEY = your_emailjs_public_key
In Vite, environment variables must be prefixed with VITE_ to be exposed to your application. This is a security feature to prevent accidentally exposing server-side secrets.
Getting EmailJS Credentials
Create an EmailJS account
Get your Public Key
Navigate to Account → API Keys to find your Public Key (VITE_PUBLIC_KEY).
Create an Email Service
Go to Email Services → Add New Service. Connect your email provider and note the Service ID (VITE_SEVICE_ID).
Create an Email Template
Go to Email Templates → Create New Template. Customize your template and note the Template ID (VITE_TEMPLATE_ID).
Deployment Platforms
Vercel
Netlify
GitHub Pages
Cloudflare Pages
Deploy to Vercel Vercel offers the simplest deployment experience with automatic deployments from Git.
Install Vercel CLI (Optional)
Deploy via CLI
From your project root: Follow the prompts to link your project.
Or Deploy via Git Integration
Push your code to GitHub, GitLab, or Bitbucket
Go to vercel.com and sign in
Click “Add New Project”
Import your repository
Vercel auto-detects Vite configuration
Click “Deploy”
Configure Environment Variables
In your Vercel project dashboard:
Go to Settings → Environment Variables
Add each variable:
VITE_SEVICE_ID
VITE_TEMPLATE_ID
VITE_PUBLIC_KEY
Select all environments (Production, Preview, Development)
Save and redeploy
Vercel Configuration (Optional) Create vercel.json for custom configuration: {
"buildCommand" : "npm run build" ,
"outputDirectory" : "dist" ,
"framework" : "vite"
}
Vercel provides automatic HTTPS, CDN distribution, and instant rollbacks. Each Git push creates a preview deployment.
Deploy to Netlify Netlify offers continuous deployment, serverless functions, and form handling.
Deploy via Drag & Drop
Quick deployment for testing:
Run npm run build locally
Go to app.netlify.com
Drag the dist folder to the deploy zone
Or Deploy via Git Integration
For automatic deployments:
Push your code to GitHub, GitLab, or Bitbucket
Go to app.netlify.com and sign in
Click “Add new site” → “Import an existing project”
Connect your repository
Configure build settings:
Build command : npm run build
Publish directory : dist
Click “Deploy site”
Configure Environment Variables
In your Netlify site dashboard:
Go to Site settings → Environment variables
Click “Add a variable”
Add each variable:
VITE_SEVICE_ID
VITE_TEMPLATE_ID
VITE_PUBLIC_KEY
Save and trigger a new deploy
Netlify Configuration Create netlify.toml for advanced configuration: [ build ]
command = "npm run build"
publish = "dist"
[[ redirects ]]
from = "/*"
to = "/index.html"
status = 200
The redirect rule is crucial for React Router to work correctly. Without it, direct navigation to routes will return 404 errors.
Deploy to GitHub Pages GitHub Pages offers free hosting for static sites directly from your repository.
Install gh-pages package
npm install --save-dev gh-pages
Update vite.config.js
Set the base URL to your repository name: export default defineConfig ({
base: '/your-repo-name/' ,
// ... other config
})
Add deployment scripts
Update package.json: {
"scripts" : {
"dev" : "vite" ,
"build" : "vite build" ,
"preview" : "vite preview" ,
"predeploy" : "npm run build" ,
"deploy" : "gh-pages -d dist"
}
}
Deploy
This builds your project and pushes the dist folder to the gh-pages branch.
Enable GitHub Pages
Go to your repository on GitHub
Navigate to Settings → Pages
Under “Source”, select the gh-pages branch
Click “Save”
Your site will be available at https://username.github.io/your-repo-name/ Environment Variables on GitHub Pages GitHub Pages doesn’t support server-side environment variables. You have two options:
Option 1: Use GitHub Actions (Recommended)Create .github/workflows/deploy.yml: .github/workflows/deploy.yml
name : Deploy to GitHub Pages
on :
push :
branches : [ main ]
workflow_dispatch :
permissions :
contents : read
pages : write
id-token : write
jobs :
build :
runs-on : ubuntu-latest
steps :
- uses : actions/checkout@v4
- name : Setup Node
uses : actions/setup-node@v4
with :
node-version : '20'
cache : 'npm'
- name : Install dependencies
run : npm ci
- name : Build
env :
VITE_SEVICE_ID : ${{ secrets.VITE_SEVICE_ID }}
VITE_TEMPLATE_ID : ${{ secrets.VITE_TEMPLATE_ID }}
VITE_PUBLIC_KEY : ${{ secrets.VITE_PUBLIC_KEY }}
run : npm run build
- name : Upload artifact
uses : actions/upload-pages-artifact@v3
with :
path : './dist'
deploy :
environment :
name : github-pages
url : ${{ steps.deployment.outputs.page_url }}
runs-on : ubuntu-latest
needs : build
steps :
- name : Deploy to GitHub Pages
id : deployment
uses : actions/deploy-pages@v4
Then add secrets in Settings → Secrets and variables → Actions. Option 2: Hardcode values (Not recommended for sensitive data)Create .env.production and commit it (only if values are public): VITE_SEVICE_ID = your_service_id
VITE_TEMPLATE_ID = your_template_id
VITE_PUBLIC_KEY = your_public_key
Deploy to Cloudflare Pages Cloudflare Pages offers fast global CDN and unlimited bandwidth.
Connect your repository
Go to dash.cloudflare.com
Navigate to Pages
Click “Create a project” → “Connect to Git”
Select your repository
Configure build settings
Framework preset : Vite
Build command : npm run build
Build output directory : dist
Add environment variables
Go to Settings → Environment variables
Add each variable for Production:
VITE_SEVICE_ID
VITE_TEMPLATE_ID
VITE_PUBLIC_KEY
Deploy
Click “Save and Deploy”. Your site will be live on your-project.pages.dev
Cloudflare Pages automatically handles SPA routing for React Router. No additional configuration needed.
Custom Domain Setup
All platforms support custom domains:
Purchase a domain
Buy a domain from providers like Namecheap, Google Domains, or Cloudflare.
Configure DNS
Add DNS records pointing to your hosting platform: For Vercel/Netlify/Cloudflare:
Add CNAME record: www → your-site.platform.com
Add A record for apex domain (provided by platform)
Add domain in platform settings
Vercel : Settings → Domains
Netlify : Site settings → Domain management
GitHub Pages : Settings → Pages → Custom domain
Cloudflare Pages : Custom domains → Set up a custom domain
Wait for DNS propagation
DNS changes can take 24-48 hours to propagate globally.
Common Deployment Issues
Issue: Blank Page After Deployment
Possible Causes:
Incorrect base configuration in vite.config.js
JavaScript errors (check browser console)
Missing environment variables
Solution:
// For root domain deployment
export default defineConfig ({
base: '/' ,
})
// For subdirectory deployment
export default defineConfig ({
base: '/subdirectory/' ,
})
Issue: 404 on Page Refresh
Problem : Refreshing any route except home shows 404
Solution : Configure your hosting platform to redirect all routes to index.html:
Netlify
Vercel
Cloudflare Pages
[[ redirects ]]
from = "/*"
to = "/index.html"
status = 200
Issue: Environment Variables Not Working
Checklist:
Issue: Contact Form Not Working
Common Problems:
CORS errors : Verify EmailJS domain is whitelisted
Invalid credentials : Double-check Service ID, Template ID, and Public Key
Missing environment variables : Ensure all three variables are set correctly
Testing:
// Add console logs in Contact.jsx to debug
console . log ( 'Service ID:' , import . meta . env . VITE_SEVICE_ID );
console . log ( 'Template ID:' , import . meta . env . VITE_TEMPLATE_ID );
console . log ( 'Public Key:' , import . meta . env . VITE_PUBLIC_KEY );
Remove debug console logs before production deployment to avoid exposing sensitive data in browser console.
Performance Optimization
Enable Compression
Most platforms enable gzip/brotli compression automatically. Verify in browser DevTools:
Check Content-Encoding header in Network tab
Should show gzip or br
Configure Caching
Vite automatically adds content hashes to filenames for cache busting:
assets/index-a1b2c3d4.js
assets/index-e5f6g7h8.css
This allows aggressive caching of assets while ensuring updates are always fetched.
Optimize Images
Before deployment:
Compress images using tools like TinyPNG or Squoosh
Use modern formats (WebP, AVIF) with fallbacks
Implement lazy loading for below-the-fold images
Monitoring and Analytics
Add Analytics
Google Analytics:
// Add to index.html
< script async src = "https://www.googletagmanager.com/gtag/js?id=GA_MEASUREMENT_ID" ></ script >
< script >
window.dataLayer = window.dataLayer || [];
function gtag() { dataLayer . push ( arguments ); }
gtag('js', new Date());
gtag('config', 'GA_MEASUREMENT_ID');
</ script >
Vercel Analytics:
npm install @vercel/analytics
import { Analytics } from '@vercel/analytics/react' ;
function App () {
return (
<>
{ /* Your app */ }
< Analytics />
</>
);
}
Error Tracking
Consider integrating error tracking services:
Sentry : Comprehensive error tracking
LogRocket : Session replay and monitoring
Rollbar : Real-time error monitoring
Deployment Checklist
Before going live:
Continuous Deployment
All recommended platforms support automatic deployments:
Push to Git : Commit and push changes to your repository
Automatic Build : Platform detects changes and triggers build
Deploy : New version goes live automatically
Rollback : Instantly revert to previous deployment if needed
Set up branch-based deployments: production branch for live site, staging branch for testing.
Next Steps
Build Configuration Learn about build optimization and configuration
Customization Guide Customize your portfolio’s design and content