Deploy a Personal Website to Vercel

Deploy a responsive portfolio website to Vercel's global CDN using the CLI.

Introduction

30 Second Summary

You have skills, projects, and ideas worth sharing. But getting a personal website live on the internet has traditionally meant wrestling with hosting providers, FTP uploads, and monthly fees.

In this project, you will build a personal portfolio website and deploy it to Vercel using the Vercel CLI. You'll go from a local HTML file to a live site on the internet in seconds.

What You'll Build

A responsive HTML/CSS portfolio website deployed to Vercel's global CDN, accessible via a unique .vercel.app URL.

By the end of this project, you'll have:

  • A live portfolio website accessible from anywhere in the world.
  • Hands-on experience with the Vercel CLI deployment workflow including preview and production deployments.
  • A repeatable workflow for deploying any future web project to Vercel in seconds.
  • Secret Mission: Add a dark mode toggle to your portfolio using JavaScript.

Are there any prerequisites?

None. This project includes full setup instructions for every tool you need, including Node.js and the Vercel CLI. No prior experience with web hosting or deployment is required.

Set Up Your Tools

Before you can deploy anything to the internet, you need two things on your machine: a JavaScript runtime (Node.js) and the Vercel command-line tool.

In this step, you'll install both tools and connect to your free Vercel account. Once everything is set up, deploying will only take a single command.

In this step, get ready to:
  • Install Node.js (version 18 or higher).
  • Install the Vercel CLI globally.
  • Create a Vercel account and authenticate in your terminal.
Install Node.js

Node.js is the JavaScript runtime that powers the Vercel CLI. You need version 18 or higher installed on your machine.

  • Press Cmd+Space (macOS) or the Windows key (Windows) to open your search bar.
  • Type Terminal and press Enter to open it.
  • Check if Node.js is already installed by running this command:
node --version

Look at the output in your terminal and pick the tab below that matches what you see.

✔️ I see version 18 or higher

You should see something like v22.17.0 or v24.16.0 (the exact number may differ). Any version starting with 18 or above is perfect.

Node.js is ready. Move on to the next substep.

ⓧ I see an older version

If your version number starts with a number lower than 18 (for example v16.14.0), you need to upgrade.

  • Go to nodejs.org/en/download in your browser.
  • Download the LTS installer for your operating system.
  • Run the installer and accept the defaults at each step.
  • Close your terminal, reopen it, and run node --version again to confirm the new version.

Why close and reopen the terminal?

Your terminal loads the path to installed programs when it first opens. After installing a new version of Node.js, the old terminal session still points to the old version. Reopening gives it a fresh start.

ⓧ Command not found

This means Node.js is not installed on your machine yet. Let's fix that.

  • Go to nodejs.org/en/download in your browser.
  • Download the LTS installer for your operating system (macOS or Windows).
  • Run the installer and accept the defaults at each step.
  • Close your terminal, reopen it, and run node --version again to confirm Node.js is installed.

You should now see a version number starting with 18 or higher.

Install the Vercel CLI

The Vercel CLI is the tool you'll use to deploy your website directly from the terminal. It ships as an npm package (npm comes bundled with Node.js).

  • Install the Vercel CLI globally by running this command:
npm i -g vercel

What does this command do?

The -g flag means "global." It installs the vercel command so you can run it from any folder on your machine, not just this project.

  • Confirm the installation worked by running:
vercel --version

You should see a version number printed in the terminal. The exact number does not matter as long as you see one.

Seeing 'command not found'?

This usually means the global npm bin directory is not in your system's PATH. Try running npx vercel --version instead. If that works, you can use npx vercel in place of vercel for all commands in this project.

Help me fix 'vercel: command not found' after running npm i -g vercel

Create a Vercel account and log in

Vercel's free Hobby plan gives you everything you need to host personal projects. No credit card required.

  • Go to vercel.com/signup in your browser.
  • Create a free account using your email, GitHub, GitLab, or Bitbucket.
  • Once your account is created, return to your terminal.
  • Log in to Vercel from the terminal by running this command:
vercel login

What happens when you run this?

The CLI opens a browser tab where you approve the login request. After you confirm in the browser, the terminal shows a success message. You only need to do this once.

  • Switch to the browser tab that opened and approve the login request.
  • Return to your terminal. You should see a confirmation message indicating you are now logged in.

Browser didn't open?

If no browser tab appeared, look in your terminal for a URL. Copy and paste it into your browser manually to complete the login.

Help me log in to Vercel from my terminal

  • Press Cmd+Space (macOS) or the Windows key (Windows) to open your search bar.
  • Type Visual Studio Code and press Enter to open it.

Don't have VS Code installed?

Download it for free from code.visualstudio.com. Run the installer and accept all defaults. Any code editor works for this project, but VS Code is what the instructions reference.

Your tools are ready. Next up, you'll build the portfolio website that you're about to deploy to the world.

Build Your Portfolio Website

Your tools are ready. Now it's time to build the website you'll deploy to Vercel.

In this step, you'll create a clean, responsive portfolio page using HTML and CSS. The page will showcase your name, a short bio, your skills, and links to your profiles.

In this step, get ready to:
  • Create your project folder and HTML structure.
  • Style your portfolio with responsive CSS.
  • Preview the site locally in your browser.
Create your project folder

Before writing any code, you need a dedicated folder for your project files. You'll create this on your Desktop so it's easy to find.

  • In VS Code, open the integrated terminal by pressing Ctrl+` (macOS) or Ctrl+` (Windows).
  • Move to your Desktop by running this command:
cd ~/Desktop
  • Create your project folder and move into it by running these commands:
mkdir portfolio-site
cd portfolio-site
  • Confirm the folder exists by running:
pwd

You should see a path ending in portfolio-site in the output.

  • Now open this folder in VS Code. Click File in the top menu bar.
  • Click Open Folder.
  • Navigate to your Desktop, select the portfolio-site folder, then click Open.

Why open the folder this way?

Opening a folder in VS Code sets it as your workspace. This means the Explorer sidebar shows your project files and the integrated terminal starts in that folder automatically.

Create the HTML structure

Your portfolio needs an index.html file. This is the entry point that browsers load when someone visits your site.

  • In the VS Code Explorer sidebar, click the New File icon (a page with a plus sign).
  • Type index.html and press Enter.
  • Paste the following code into index.html:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>My Portfolio</title>
    <!-- Link to external stylesheet -->
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <!-- Header with your name and tagline -->
    <header>
        <h1>Alex Johnson</h1>
        <p class="tagline">Aspiring Web Developer</p>
    </header>

    <main>
        <!-- About section introducing yourself -->
        <section class="about">
            <h2>About Me</h2>
            <p>Hi! I'm Alex, a curious learner diving into web development. I love building things for the web and learning new technologies. This portfolio is hosted on Vercel!</p>
        </section>

        <!-- Skills displayed in a grid of cards -->
        <section class="skills">
            <h2>Skills</h2>
            <div class="skills-grid">
                <div class="skill-card">HTML</div>
                <div class="skill-card">CSS</div>
                <div class="skill-card">JavaScript</div>
                <div class="skill-card">Git</div>
                <div class="skill-card">Vercel</div>
                <div class="skill-card">VS Code</div>
            </div>
        </section>

        <!-- Links to your online profiles -->
        <section class="links">
            <h2>Find Me Online</h2>
            <ul>
                <li><a href="https://github.com">GitHub</a></li>
                <li><a href="https://linkedin.com">LinkedIn</a></li>
            </ul>
        </section>
    </main>

    <footer>
        <p>Built and deployed with Vercel</p>
    </footer>
</body>
</html>

What does this code do?

This HTML creates the structure of your portfolio page with four main sections:

  • A header displaying your name and tagline.
  • An about section with a short bio paragraph.
  • A skills section with six cards arranged in a grid.
  • A links section with profile links and a footer.

The <link rel="stylesheet" href="style.css"> line connects the HTML to a CSS file you'll create next.

  • Save index.html by pressing Cmd+S (macOS) or Ctrl+S (Windows).

Don't see the file in the sidebar?

Make sure you opened the portfolio-site folder (not your Desktop or another parent folder). The file should appear in the Explorer panel on the left. If the Explorer is hidden, press Cmd+Shift+E (macOS) or Ctrl+Shift+E (Windows) to reveal it.

Help me find my index.html file in VS Code.

Style your portfolio

The HTML gives your page structure, but without CSS it looks like plain text. You'll now add a stylesheet that turns your portfolio into a polished, responsive page.

  • Create a new file in the Explorer sidebar called style.css.
  • Paste the following foundation styles into style.css:
/* Reset default browser styles */
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

/* Base page layout and typography */
body {
    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    line-height: 1.6;
    color: #333;
    background-color: #f8f9fa;
    max-width: 800px;
    margin: 0 auto;
    padding: 2rem;
}

/* Centered header area */
header {
    text-align: center;
    padding: 3rem 0;
}

header h1 {
    font-size: 2.5rem;
    color: #1a1a2e;
    margin-bottom: 0.5rem;
}

.tagline {
    font-size: 1.2rem;
    color: #666;
}

/* Stack sections vertically with spacing */
main {
    display: flex;
    flex-direction: column;
    gap: 2.5rem;
}

/* Section heading style with underline */
section h2 {
    font-size: 1.5rem;
    color: #1a1a2e;
    margin-bottom: 1rem;
    padding-bottom: 0.5rem;
    border-bottom: 2px solid #e0e0e0;
}

.about p {
    font-size: 1.1rem;
    color: #555;
}

What does this code do?

These styles handle the page foundation. The * reset removes default browser margins so your design starts from a clean slate. The body rule centres the page at 800px wide with comfortable padding.

The main uses flexbox to stack sections with even gaps. Each section h2 gets a subtle underline border to separate content areas visually.

  • Now add the component styles below the code you just pasted (still in style.css):
/* Grid layout for skill cards */
.skills-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
    gap: 1rem;
}

/* Individual skill card with hover lift */
.skill-card {
    background: white;
    padding: 1rem;
    border-radius: 8px;
    text-align: center;
    font-weight: 600;
    color: #1a1a2e;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
    transition: transform 0.2s;
}

.skill-card:hover {
    transform: translateY(-2px);
}

/* Horizontal link list */
.links ul {
    list-style: none;
    display: flex;
    gap: 1.5rem;
}

.links a {
    color: #0070f3;
    text-decoration: none;
    font-size: 1.1rem;
    font-weight: 500;
}

.links a:hover {
    text-decoration: underline;
}

/* Footer text */
footer {
    text-align: center;
    padding: 3rem 0 1rem;
    color: #999;
    font-size: 0.9rem;
}

/* Responsive adjustments for mobile */
@media (max-width: 600px) {
    body {
        padding: 1rem;
    }

    header h1 {
        font-size: 2rem;
    }

    .skills-grid {
        grid-template-columns: repeat(2, 1fr);
    }

    .links ul {
        flex-direction: column;
        gap: 0.75rem;
    }
}

What does this code do?

The .skills-grid uses CSS Grid to automatically arrange skill cards in rows. Each card has a subtle shadow and lifts slightly on hover thanks to transform: translateY(-2px).

The @media block at the bottom makes the layout adapt to smaller screens. On mobile, the skills grid shrinks to two columns and the links stack vertically.

  • Save style.css.

Seeing unstyled text when you preview later?

Double check that your style.css file is in the same folder as index.html. The <link> tag in the HTML looks for style.css right next to it. If the file is nested in a subfolder, the link won't resolve.

Help me figure out why my CSS isn't loading.

✔️ Awesome, I've got everything!

Great. Double check you've saved both files.

ⓧ I'd like to double check the full code

Here's what index.html should look like:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>My Portfolio</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <header>
        <h1>Alex Johnson</h1>
        <p class="tagline">Aspiring Web Developer</p>
    </header>

    <main>
        <section class="about">
            <h2>About Me</h2>
            <p>Hi! I'm Alex, a curious learner diving into web development. I love building things for the web and learning new technologies. This portfolio is hosted on Vercel!</p>
        </section>

        <section class="skills">
            <h2>Skills</h2>
            <div class="skills-grid">
                <div class="skill-card">HTML</div>
                <div class="skill-card">CSS</div>
                <div class="skill-card">JavaScript</div>
                <div class="skill-card">Git</div>
                <div class="skill-card">Vercel</div>
                <div class="skill-card">VS Code</div>
            </div>
        </section>

        <section class="links">
            <h2>Find Me Online</h2>
            <ul>
                <li><a href="https://github.com">GitHub</a></li>
                <li><a href="https://linkedin.com">LinkedIn</a></li>
            </ul>
        </section>
    </main>

    <footer>
        <p>Built and deployed with Vercel</p>
    </footer>
</body>
</html>

Here's what style.css should look like:

* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

body {
    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    line-height: 1.6;
    color: #333;
    background-color: #f8f9fa;
    max-width: 800px;
    margin: 0 auto;
    padding: 2rem;
}

header {
    text-align: center;
    padding: 3rem 0;
}

header h1 {
    font-size: 2.5rem;
    color: #1a1a2e;
    margin-bottom: 0.5rem;
}

.tagline {
    font-size: 1.2rem;
    color: #666;
}

main {
    display: flex;
    flex-direction: column;
    gap: 2.5rem;
}

section h2 {
    font-size: 1.5rem;
    color: #1a1a2e;
    margin-bottom: 1rem;
    padding-bottom: 0.5rem;
    border-bottom: 2px solid #e0e0e0;
}

.about p {
    font-size: 1.1rem;
    color: #555;
}

.skills-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
    gap: 1rem;
}

.skill-card {
    background: white;
    padding: 1rem;
    border-radius: 8px;
    text-align: center;
    font-weight: 600;
    color: #1a1a2e;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
    transition: transform 0.2s;
}

.skill-card:hover {
    transform: translateY(-2px);
}

.links ul {
    list-style: none;
    display: flex;
    gap: 1.5rem;
}

.links a {
    color: #0070f3;
    text-decoration: none;
    font-size: 1.1rem;
    font-weight: 500;
}

.links a:hover {
    text-decoration: underline;
}

footer {
    text-align: center;
    padding: 3rem 0 1rem;
    color: #999;
    font-size: 0.9rem;
}

@media (max-width: 600px) {
    body {
        padding: 1rem;
    }

    header h1 {
        font-size: 2rem;
    }

    .skills-grid {
        grid-template-columns: repeat(2, 1fr);
    }

    .links ul {
        flex-direction: column;
        gap: 0.75rem;
    }
}
Preview your site locally

Before deploying to the internet, you should check that everything looks good on your own machine.

  • In the VS Code Explorer sidebar, right-click index.html.
  • Select Reveal in Finder (macOS) or Reveal in File Explorer (Windows).
  • Double-click index.html in your file browser to open it in your default web browser.

You should see a centered page with your name in large text at the top, six skill cards arranged in a grid, and two blue links at the bottom.

Page looks like plain text with no styling?

Check that both index.html and style.css are saved in the same portfolio-site folder. Open VS Code's Explorer and confirm both files appear at the same level (not one inside a subfolder).

Help me troubleshoot my portfolio preview.

Your portfolio looks great locally. Next up, you'll deploy it to Vercel and see it live on the internet.

Deploy a Preview to Vercel

Your portfolio looks great locally. Now it is time to put it on the internet where anyone can see it.

The Vercel CLI makes this surprisingly fast. You will run a single command, answer a few setup questions, and get a live URL in seconds.

In this step, get ready to:
  • Deploy your portfolio to a live preview URL using the Vercel CLI.
  • Visit your site on the internet and confirm it works.
  • Understand the preview deployment workflow.
Run your first deployment

The vercel command handles everything: it links your local folder to a Vercel project, detects that you have a static site, and deploys it.

  • Switch back to your terminal.
  • Make sure you are inside your project folder (the one containing index.html and style.css).
  • Run your first deployment by entering this command:
vercel

What will the CLI ask me?

The Vercel CLI walks you through a short interactive setup the first time you deploy a directory. Press Enter to accept the default for each prompt:

  • Set up and deploy? Press Enter to confirm yes.
  • Which scope do you want to deploy to? Press Enter to select your personal account.
  • Link to existing project? Press Enter to say no (you are creating a new one).
  • What's your project's name? Press Enter to accept the default (your folder name).
  • In which directory is your code located? Press Enter to accept ./ (the current folder).
  • Want to override the settings? Press Enter to say no.

The CLI auto-detects that your project has no framework and sets it to Other. This means it serves your files directly with no build step needed.

  • After a few seconds, the CLI finishes and prints a Preview URL in your terminal.
  • It looks something like my-portfolio-xxxx.vercel.app.

Seeing an error about authentication?

If you see a message about not being logged in, run vercel login first and complete the authentication flow. Then try vercel again.

If you see a permissions error on macOS when running the command, try prefixing it with sudo or check that your terminal has the correct folder permissions.

Why is my Vercel deployment failing?

Visit your preview URL

The CLI just gave you a live URL. Your portfolio is already on the internet.

  • Copy the preview URL from your terminal output.
  • Paste it into your browser's address bar and press Enter.

You should see your portfolio site looking exactly the same as it did locally. The header, the skills grid, and the links section are all live on the internet.

What is a preview deployment?

A preview deployment is a temporary deployment with a unique URL. It lets you test changes before making them official.

This preview URL is not your permanent production address yet. It is a staging ground where you can verify everything looks correct before shipping to production.

Site not loading at the preview URL?

Make sure you copied the full URL from the terminal output, including the https:// prefix.

If the page appears blank, check that your index.html file is in the root of your project folder (not nested inside a subfolder).

Why is my Vercel preview showing a blank page?

Understand the preview workflow

You just experienced Vercel's core deployment model: preview first, then ship to production.

Why preview before production?

Every time you run vercel without the --prod flag, you get a brand new preview URL. This means you can test changes safely without affecting your live site.

Once you are happy with a preview, you promote it to production with a separate command. This two-step workflow protects you from accidentally breaking a live site.

Your deployment workflow is now simple: make changes locally, run vercel to preview, and then ship to production when ready. Next up, you will ship your portfolio to its permanent production URL.

Deploy to Production

In the previous step, you deployed a preview of your portfolio and confirmed it looks good on a unique URL.

Now it is time to go live. A production deployment assigns your site to a permanent .vercel.app domain that you can share with anyone.

In this step, get ready to:
  • Ship your portfolio to production with a single command.
  • Visit your permanent production URL in the browser.
  • Make a small edit and redeploy to see how fast updates go live.
Ship to production

Preview deployments are great for testing, but they use temporary URLs that change every time you deploy. Production deployments lock your site to a permanent .vercel.app domain.

  • Deploy your portfolio to production by running this command in your terminal:
vercel --prod

What does this command do?

The --prod flag tells the Vercel CLI to create a production deployment instead of a preview. This assigns the deployment to your project's permanent .vercel.app domain.

Without --prod, every deployment gets a unique preview URL. With --prod, the deployment replaces whatever is currently live on your production domain.

  • Wait for the deployment to finish. The CLI outputs a production URL when it completes.

Seeing a permissions error?

Make sure you are inside your project folder (the one containing index.html) when you run the command. If you are in the wrong directory, the CLI cannot find your project.

Also confirm you are still logged in by running vercel whoami. If it says you are not authenticated, run vercel login again.

Help me troubleshoot my Vercel production deployment

Visit your production URL

Your site is now live on the internet with a permanent address. Anyone with the link can see your portfolio.

  • Copy the production URL from the terminal output. It follows the format your-project-name.vercel.app.
  • Paste the URL into your browser and press Enter.
  • Confirm you see your full portfolio with your name, about section, skills grid, and links.

What is the difference between preview and production?

Preview deployments get a unique URL every time you run vercel (without --prod). They are useful for testing changes before anyone else sees them.

Production deployments are assigned to your project's permanent .vercel.app domain. This is the URL you share publicly. Every time you redeploy with --prod, the same domain points to your latest code.

Make a change and redeploy

The real power of this workflow is speed. You can push updates live in seconds without touching a dashboard or waiting for a build pipeline.

  • Switch back to VS Code and open index.html.
  • Find this line inside the <header> section:
<p class="tagline">Aspiring Web Developer</p>
  • Change the text inside the <p> tag to something new. For example:
<p class="tagline">Building cool things for the web</p>
  • Save index.html.
  • Redeploy to production by running this command:
vercel --prod
  • Once the deployment finishes, refresh your production URL in the browser.
  • Confirm your updated tagline appears on the live site.

Why is this so fast?

Vercel serves static files (HTML, CSS, JS) directly from a global CDN. There is no build step for plain HTML/CSS sites, so the CLI just uploads your files and they are live almost instantly.

Not seeing your change on the live site?

Make sure you saved index.html before running vercel --prod. The CLI deploys whatever is on disk at the moment you run it.

Try a hard refresh in your browser: Cmd+Shift+R (macOS) or Ctrl+Shift+R (Windows). This clears the browser cache and fetches the latest version from Vercel.

Help me figure out why my redeployment is not showing updated content

Secret mission

Add Dark Mode

Your portfolio looks great, but what about visitors who prefer a darker interface? Add a dark mode toggle that remembers each visitor's preference across page reloads.

Clean Up Your Resources

Clean Up Your Resources

This project runs entirely locally and deploys to Vercel's free Hobby plan, so there are no ongoing costs. Decide whether to keep your resources running, pause them to come back later, or delete them entirely.

Resources you used:

  • Local project folder with index.html, style.css, and script.js.
  • Vercel project with production deployment (hosted on the free Hobby plan).
  • Vercel CLI installed globally via npm.
  • Vercel account (free Hobby plan).

Keep everything running

No action needed. Choose this if you're still actively building or want your portfolio to stay live at its .vercel.app URL.

  • Your site stays live on Vercel's free Hobby plan with no charges.
  • The Vercel CLI remains installed on your machine for future deployments.
  • Your local project files remain on your Desktop.

Pause - I'll come back to this later

Shut down running processes to free up space. Your site stays live on Vercel (no cost), but you can remove local tools and reinstall later.

  • Your Vercel deployment stays live at no cost. No action needed on the Vercel side.
  • Optionally remove the Vercel CLI to reclaim disk space by running:
npm uninstall -g vercel
  • You can reinstall it later with npm i -g vercel when you're ready to deploy again.

Delete - I don't want to use this again

Remove all project resources and start fresh. This takes your site offline and removes local files.

  • Delete your Vercel project (and all its deployments) by running this command from your project folder:
vercel project rm

What does this command do?

The CLI will prompt you to confirm by entering the project name. Once confirmed, this removes the project, all its deployments, and takes your site offline.

  • Uninstall the Vercel CLI by running:
npm uninstall -g vercel
  • Delete your local project folder. On macOS or Linux, run:
cd ~/Desktop
rm -rf [[PROJECT_FOLDER="your-project-folder-name"]]
  • On Windows, run:
cd ~\Desktop
Remove-Item -Recurse -Force [[PROJECT_FOLDER="your-project-folder-name"]]
  • To delete your Vercel account entirely, open the Vercel Dashboard in your browser.
  • Click your avatar in the top-right corner, then select Account Settings.
  • Scroll to the bottom of the General page.
  • Click Delete Personal Account and follow the confirmation prompts. This is permanent and removes all projects and deployments.

Nice Work!

Nice Work!

You did it. Your personal portfolio website is live on the internet, hosted on Vercel's global CDN with automatic HTTPS.

You've learned how to:

  • Built a responsive HTML/CSS portfolio website from scratch and previewed it locally.
  • Installed the Vercel CLI and used it to deploy a live website to the internet in seconds.
  • Used preview deployments to test changes safely, then shipped to production with a single command (vercel --prod).
  • Added a dark mode toggle with JavaScript and localStorage persistence, then redeployed to production.

Ready to quiz yourself?