- Deploying
6. Deploying
Part 6 of the From CV to Site tutorial series.
Prerequisites
- Completed Tutorials 4 and 5
- Site runs locally without errors via
pnpm dev - Git repository initialized and committed
What this tutorial produces
A production site deployed to Vercel and, optionally, mapped to a custom domain over HTTPS.
Deployment stack
| Component | Provider | Cost |
|---|---|---|
| Hosting, build, CDN | Vercel | Free (Hobby tier) |
| Domain registration | Namecheap, Cloudflare, Google Domains, etc. | 10 to 20 USD / year |
| DNS | Vercel, Cloudflare, or your registrar | Free |
| SSL certificate | Vercel (automatic) | Free |
Pushing the project to GitHub
Create a repository on GitHub, then push the local project.
# at the project root
git remote add origin git@github.com:YOUR_USERNAME/my-site.git
git branch -M main
git push -u origin main
Replace YOUR_USERNAME and my-site with your GitHub username and repository name.
Creating a Vercel account
- Visit vercel.com/signup
- Sign up using your GitHub account
- Accept the terms for the Hobby tier
Connecting GitHub to Vercel
- From the Vercel dashboard, click Add New > Project
- Select Import Git Repository
- Authorize Vercel to access your GitHub account if prompted
- Select the repository you pushed above
- Click Import
First deployment
Vercel auto-detects Next.js. Leave the defaults and click Deploy.
- Build command:
pnpm build(auto-detected) - Output directory:
.next(auto-detected) - Install command:
pnpm install(auto-detected)
The first build typically completes in two to four minutes. Vercel provides a live URL at your-project.vercel.app when the build finishes.
Verifying the deployment
Open the Vercel-provided URL. Check:
- The home page loads
- Navigation links work (
/research,/projects, etc.) - Fonts and styles render correctly
- Images load
If any page 404s or shows an error, check the Deployments tab in Vercel for build logs.
Continuous deployment
Vercel redeploys automatically whenever you push to main. For feature work, push to a branch and Vercel will provide a preview URL for that branch without affecting production.
git checkout -b update-publications
# make changes
git commit -am "Update publications"
git push -u origin update-publications
# preview URL appears in the Vercel dashboard
Acquiring a custom domain
Register a domain at any registrar. Common choices:
Expected annual cost: 10 to 20 USD for common TLDs (.com, .org, .net). Some academic TLDs (.edu.xx, .ac.xx) are restricted.
Connecting the custom domain
- In Vercel, open your project > Settings > Domains
- Enter your domain (e.g.,
yourlab.com) and click Add - Vercel displays the required DNS records
You will typically see two options:
- Recommended: change nameservers at your registrar to Vercel’s nameservers
- Alternative: keep your registrar’s nameservers and add
AandCNAMErecords manually
For most users, adding DNS records at the registrar is sufficient. Vercel typically instructs you to add:
- An
Arecord for@pointing to76.76.21.21 - A
CNAMErecord forwwwpointing tocname.vercel-dns.com
Exact values are provided by Vercel; follow the values displayed in the dashboard, not the examples above.
Verifying DNS
DNS propagation usually completes within a few minutes. Vercel’s Domains tab displays a green check when records are detected.
Verify from the command line:
dig yourlab.com +short
# Expected: 76.76.21.21 (or Vercel's current IP)
SSL certificate
Vercel provisions and renews SSL certificates automatically once DNS resolves. No configuration is required. HTTPS should be available within minutes of DNS propagation.
Setting up redirects
Decide on a canonical version of your URL (www or non-www) and redirect the other to it.
In next.config.ts:
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
async redirects() {
return [
{
source: "/:path*",
has: [{ type: "host", value: "www.yourlab.com" }],
destination: "https://yourlab.com/:path*",
permanent: true,
},
];
},
};
export default nextConfig;
Commit and push. Vercel rebuilds and applies the redirect.
Environment variables
Environment variables are set per project in Vercel under Settings > Environment Variables. Add them separately for Production, Preview, and Development environments.
Common variables for academic sites:
NEXT_PUBLIC_SITE_URL: canonical domain (e.g.,https://yourlab.com)CONTACT_EMAIL: address used in contact forms, if applicable
Access variables in your code:
const siteUrl = process.env.NEXT_PUBLIC_SITE_URL;
Variables prefixed with NEXT_PUBLIC_ are exposed to the browser. Others remain server-only.
Production checklist
Before announcing the site:
- All internal links resolve
- Meta tags are set per route (
title,description) - A favicon exists at
src/app/favicon.ico - The
public/directory is free of unused files - Publications render and link correctly
- The contact page lists accurate affiliations
- HTTPS loads without browser warnings
- The site appears correctly at mobile, tablet, and desktop widths
Rolling back a bad deployment
From the Vercel dashboard, open Deployments, select a previous successful deployment, and click Promote to Production. This reverts the live site without code changes.
Adding Vercel Analytics
Vercel provides built-in analytics integrated with the deployment platform. No cookies are set, so no consent banner is required.
Installation
Run from the Next.js project directory:
pnpm add @vercel/analytics
Configuration
Edit src/app/layout.tsx:
import { Analytics } from "@vercel/analytics/next";
export default function RootLayout({
children,
}: Readonly<{ children: React.ReactNode }>) {
return (
<html lang="en">
<body>
{children}
<Analytics />
</body>
</html>
);
}
Enabling the dashboard
- Visit vercel.com and select the project
- Click the Analytics tab
- Click Enable Analytics
- Select the free plan
Commit and deploy
git add .
git commit -m "Add Vercel Analytics"
git push
Data begins collecting on the next deployment. The Vercel dashboard populates within 24 hours.
Free tier limits
- 2,500 events per month
- Web Vitals (Core Web Vitals) included
- No retention limit for aggregated metrics
What Vercel Analytics tracks
- Page views
- Unique visitors
- Top pages
- Referrers
- Countries
- Device types
- Operating systems and browsers
Adding Google Analytics (optional)
Use Google Analytics when you need more detailed analytics or integration with Google Search Console. Google Analytics uses cookies and may require a consent banner depending on visitor jurisdiction.
Getting a Measurement ID
- Visit analytics.google.com
- Create an account and property
- Set up a web data stream for the domain
- Copy the Measurement ID (format:
G-XXXXXXXXXX)
Installation
pnpm add @next/third-parties
Configuration
Edit src/app/layout.tsx:
import { GoogleAnalytics } from "@next/third-parties/google";
export default function RootLayout({
children,
}: Readonly<{ children: React.ReactNode }>) {
return (
<html lang="en">
<body>{children}</body>
<GoogleAnalytics gaId="G-XXXXXXXXXX" />
</html>
);
}
Replace G-XXXXXXXXXX with your actual Measurement ID. For production, store the ID in an environment variable rather than hard-coding it:
<GoogleAnalytics gaId={process.env.NEXT_PUBLIC_GA_ID!} />
Set NEXT_PUBLIC_GA_ID in the Vercel environment variables dashboard.
Verification
After deployment, real-time reports appear immediately in the Google Analytics dashboard. Aggregate reports populate within 24 to 48 hours.
Adding Google Search Console
Google Search Console reports how the site appears in Google search results. It is recommended for any public-facing academic site.
Setup
- Visit search.google.com/search-console
- Add a property for the domain
- Verify ownership via DNS TXT record (add the record in Vercel’s or Cloudflare’s DNS settings)
- Submit the sitemap URL
Generating a sitemap
Next.js generates a sitemap automatically when you define one under the App Router. Create src/app/sitemap.ts:
import type { MetadataRoute } from "next";
const BASE_URL = "https://yourdomain.com";
export default function sitemap(): MetadataRoute.Sitemap {
const routes = ["", "/research", "/projects", "/teaching", "/news", "/contact"];
return routes.map((route) => ({
url: `${BASE_URL}${route}`,
lastModified: new Date(),
}));
}
Replace BASE_URL with your canonical domain. The sitemap is served at https://yourdomain.com/sitemap.xml.
Submit that URL in Search Console under Sitemaps.
Privacy considerations
| Service | Cookies | Consent banner | Notes |
|---|---|---|---|
| Vercel Analytics | None | Not required | GDPR/CCPA compliant by default |
| Google Analytics | Yes | Often required | GA4 anonymizes IPs by default |
| Cloudflare Web Analytics | None | Not required | Free alternative to Vercel |
| Plausible | None | Not required | Paid; hosted in the EU |
For visitors in the EU, UK, or California, consider:
- IP anonymization (enabled by default in GA4)
- A consent banner (Cookiebot, CookieYes, or a custom implementation)
- A clear privacy policy page linked in the footer
Interpreting analytics data
Metrics that matter for academic sites
- Top pages: which research themes or outputs attract readers
- Referrers: where visitors arrive from (Google Scholar, social media, institutional pages)
- Countries: the international reach of your work
- Growth over time: useful baseline for grant applications and annual reviews
Data for grant applications and reporting
Analytics can supply concrete numbers for annual reports:
- Total unique visitors over the reporting period
- Page views, as a proxy for research dissemination
- Geographic distribution of readers
- Year-over-year growth percentage
Treat these as supplementary evidence of public engagement, not as the primary measure of scholarly impact.
Next tutorial
Tutorial 7: Maintaining & Extending
Questions or feedback: open an issue on the repository or email hannahlee@virginia.edu.