Portfolio and professional email for under $5
Frontend developers guide to spin up your own portfolio for $5, complete with professional email.
Why This Project Exists
The tech industry is in a rough state, with layoffs hitting across the board. Unfortunately, I was one of those affected. While I had solid React experience, the lack of professional roles on my CV kept leading to rejections. I needed to prove my skills while making myself highly visible to potential employers, all without breaking the bank.
This guide outlines how to build and host a professional portfolio with minimal costs. There are two ways to go about it:
Quick setup – A short checklist with linked resources if you just want to get it up and running.
Detailed breakdown – A step-by-step approach for those who want to understand the reasoning and best practices behind each choice.
What You'll Need
A Gmail account (to enable a free professional email inbox)
A GitHub account
A Vercel account
A Cloudflare account
A Storyblok or Sanity account
Quick Checklist: Get Set Up Fast
If you're in a rush, here’s your rapid-fire guide to getting everything up and running. This requires external resources, which are linked.
1. Buy a Domain
Your only unavoidable cost. Cloudflare offers domain registration at cost price—no unnecessary markups. Cloudflare Registrar
2. Set Up Email Forwarding
Cloudflare allows free email forwarding, so you can have a professional email (e.g., you@yourdomain.com) that forwards to your personal inbox. How to Set Up Email Routing
3. Configure Domain Redirection
Your domain should work with and without 'www'. Set up a CNAME record in Cloudflare to ensure your website is accessible correctly.
4. Set Up Email Alias in Gmail
Once your email forwarding is configured, add an alias in Gmail to send emails from your domain address. Video Walkthrough
5. Create a Free Vercel Account
Vercel provides free hosting for personal projects, with generous usage limits. Vercel
6. Connect Vercel to Cloudflare
You'll need at least three available DNS slots to link your domain. Adding a Domain to Vercel
7. Create a GitHub Repository
This will host your portfolio code. Clone it to your local machine and generate a Next.js app using Vite. While any framework works, Next.js was my choice since it’s React-based and optimises costs with aggressive caching. Connecting GitHub to Vercel
8. Set Up a Free CMS
A headless CMS makes content management easier. Storyblok offers a free tier with generous limits, including 1 million requests per month.
Alternative: Sanity also has a free plan. Sanity Pricing
9. Optimise Build Strategy for Cost Efficiency
Use SSG (Static Site Generation) for pages that don’t change often
Use ISR (Incremental Static Regeneration) for archives or list pages
Use SSR (Server-Side Rendering) for blog post pages where real-time data is needed
10. Enable Secure Content Editing in Storyblok
For live previews within Storyblok, Next.js' experimental SSL encryption is required.
11. Set Up CI/CD Pipelines
Automate deployments using GitHub Actions. This ensures any new code updates automatically deploy via Vercel. CI/CD with Vercel & GitHub Actions
12. Deploy & Share Your Portfolio
Push a release branch, let Vercel handle deployment, and start sharing your portfolio with potential employers.
In-Depth Walkthrough

1. Acquire a Custom Domain
Investing in a custom domain is the first step to establish a professional online identity. Cloudflare offers domain registration services at cost price, ensuring affordability without hidden fees.
Steps:
Sign Up on Cloudflare: Create an account using your personal email.
Register Your Domain: Search for your desired domain name and complete the purchase.
This is by far the cheapest way to acquire a website domain and comes with a host of benefits. you get it at cost, with so many benefits which can be explored on the dashboard.

2. Set Up Email Forwarding
To maintain professionalism, configure an email address that matches your domain (e.g., yourname@yourdomain.com). Cloudflare's Email Routing allows you to forward emails from your custom domain to your personal inbox at no additional cost.
Steps:
Access Email Routing: Navigate to the Email Routing section in your Cloudflare dashboard.
Create Email Routes: Set up forwarding rules from your custom email to your personal email address.
This is another reason to go with Cloudflare, currently it doesn't have an SMPT Server or the ability to handle email inboxes, I don't think this is a planned feature either, you can always upgrade your account at a later date and integrate this with a google business account

3. Configure Domain Redirection
Ensure your website is accessible with or without the 'www' prefix by setting up proper redirection. This involves configuring DNS records to point traffic correctly.
Steps:
Add a CNAME Record: In Cloudflare's DNS settings, create a CNAME record that directs 'www.yourdomain.com' to 'yourdomain.com'.
Set Up Page Rules: Implement rules to forward traffic from 'www' to the non-'www' version or vice versa, based on your preference.

4. Integrate Custom Email with Gmail
To send emails from your custom domain using Gmail, add your new email address as an alias in your Gmail account.
Steps:
Access Gmail Settings: Go to your Gmail settings and navigate to the 'Accounts and Import' tab.
Add Another Email Address: Click on 'Add another email address' and follow the prompts to verify and configure your custom email.

5. Link your Github Project to Vercel
Vercel offers a seamless platform for deploying Next.js applications with a generous free tier, making it ideal for personal projects.
Steps:
Create a Vercel Account: Sign up using your GitHub account for easy integration.
Import Your Project: After setting up your Next.js project, import it into Vercel directly from your GitHub repository.
Configure Domain: Add your custom domain to Vercel and update DNS settings in Cloudflare as instructed by Vercel.

6. Set Up a Headless CMS with Storyblok
Managing your content efficiently is crucial. Storyblok provides a free tier suitable for developers and small projects, allowing you to handle content dynamically.
Steps:
Sign Up for Storyblok: Create an account and start a new space for your project.
Integrate with Next.js: Follow Storyblok's Next.js tutorial to connect your application with the CMS, enabling dynamic content management.
7. Build out your project
Developing your project will vary based on your chosen Content Management System (CMS). I opted for Storyblok but found its default integration, particularly the Storyblok Bridge, didn't suit my needs. The Bridge enables interactivity between your application and their CMS, allowing in-context editing via an iframe overlay. Since I didn't require this feature, I implemented an alternative approach. By the time you review this project, there should be an updated official Storyblok guide on integrating their CMS with the latest version of Next.js.
8. Implement Continuous Deployment with GitHub Actions
Automate your deployment process by setting up Continuous Integration/Continuous Deployment (CI/CD) pipelines using GitHub Actions.
Steps:
Create Workflow File: In your GitHub repository, add a
.github/workflows/deploy.yml
file defining your deployment process.Configure Secrets: Store necessary secrets like Vercel tokens in your GitHub repository settings to secure your deployments.
name: Deployment
env:
ORG_ID: ${{ secrets.ORG_ID }}
PROJECT_ID: ${{ secrets.PROJECT_ID }}
API_KEY: ${{ secrets.API_KEY }}
POST_STATUS: "published"
MAIL_SERVICE: ${{ secrets.MAIL_SERVICE }}
PUBLIC_RECIPIENT_EMAIL: ${{ secrets.RECIPIENT_EMAIL }}
on:
release:
types: [released, prereleased]
jobs:
Deploy-Production:
if: ${{ github.event.release.prerelease == false }}
runs-on: ubuntu-latest
env:
SITE_URL: ${{ secrets.PROD_URL }}
PUBLIC_CONSTRUCTION: true
steps:
- uses: actions/checkout@v2
- name: Cache NPM Cache (Production)
uses: actions/cache@v3
with:
path: ~/.npm
key: ${{ runner.os }}-npm-cache-production
- name: Install CLI
run: npm install --global cli@latest
- name: Pull Environment Information
run: cli pull --yes --environment=production --token=${{ secrets.ACCESS_TOKEN }}
- name: Build Project Artifacts
run: cli build --prod --token=${{ secrets.ACCESS_TOKEN }}
- name: Deploy Project Artifacts
run: cli deploy --prebuilt --prod --token=${{ secrets.ACCESS_TOKEN }}
Deploy-Preview:
if: ${{ github.event.release.prerelease == true }}
runs-on: ubuntu-latest
env:
SITE_URL: ${{ secrets.DEV_URL }}
PUBLIC_CONSTRUCTION: false
steps:
- uses: actions/checkout@v2
- name: Cache NPM Cache (Preview)
uses: actions/cache@v3
with:
path: ~/.npm
key: ${{ runner.os }}-npm-cache-preview
- name: Install CLI
run: npm install --global cli@latest
- name: Pull Environment Information
run: cli pull --yes --environment=preview --token=${{ secrets.ACCESS_TOKEN }}
- name: Build Project Artifacts
run: cli build --token=${{ secrets.ACCESS_TOKEN }}
- name: Deploy Project Artifacts
id: deploy
run: |
DEPLOYMENT_URL=$(cli deploy --prebuilt --token=${{ secrets.ACCESS_TOKEN }} | grep -Eo 'https://[^ ]+')
Get in touch
I am always free to discuss new projects, opportunities or any assistance you may require.
Responses usually take less than 24 hours.