DEV Community

Cover image for I got tired of my portfolio going stale, so I made one that rebuilds itself from GitHub
Louey Lahwel
Louey Lahwel

Posted on

I got tired of my portfolio going stale, so I made one that rebuilds itself from GitHub

Every developer portfolio I have made was accurate for about a month. After
that it showed what I had built last spring, and the projects I was actually
proud of lived only on GitHub. I'm a data engineer, and data that has to be
copied by hand into a second place goes stale. So I stopped copying it.

Forkfolio treats your GitHub account as
the source of truth. You sign in once, and it builds a portfolio from your
public repos, then keeps rebuilding it. Here is how that works and what
broke along the way.

Two ways a portfolio finds out you shipped something

There's a nightly job (a Vercel cron at 04:17 UTC) that re-reads every
user's public work: repos, pinned projects, languages, stars and the
contribution calendar. That alone keeps a page at most a day behind.

Pushes are faster. A GitHub webhook hits an endpoint that checks the HMAC
signature, answers 202 straight away and does the sync after the
response. GitHub disables webhooks that answer slowly, so the actual work
can't happen inside the request.

The part I underestimated was overlap. Seven different things can start a
sync: the cron, two webhooks, the Sync button, signup, installing the GitHub
App and a manual assistant refresh. One git push --tags alone sends a
delivery per ref. Each sync is a series of delete-then-write steps, so two
running at once duplicated rows and wiped settings people had changed by
hand. Now there's one lock per user. Whoever holds it does the work, anyone
else marks the user "dirty" and leaves, and the holder runs one more pass if
the mark is set when it finishes.

One data shape, 21 designs

Every template reads the same object:

type Portfolio = {
  profile: Profile;
  repos: Repo[];
  skills: Skill[];
  certifications: Certification[];
  experiences: Experience[];
  customProjects: CustomProject[];
  projects: ProjectItem[]; // repos + custom projects, merged
};
Enter fullscreen mode Exit fullscreen mode

Because of that, switching design is one click and never loses content. It
also meant the designs could be properly different instead of one layout
recoloured. There are 21 now, each its own scroll-driven page: a 1930s
cartoon with its title cards, a relief atlas, a terminal session you read by
scrolling, a Swiss type specimen. Three are free.

An assistant that only knows what you published

Each portfolio has a chat assistant for visitors. A recruiter reading your
page at 3am can ask "what have you built with Python?" and get an answer
from your actual repos. It says that it is an AI, and it answers only from
your public work.

The most useful fix there was boring. READMEs are cut into chunks before
they're embedded, and only the first chunk of a repo used to carry the
project's name. Every later chunk reached the model as unlabelled text, and
it would happily attribute one project's README to another. Now every chunk
starts with the name of the project it came from, and the prompt treats
project names as facts that must never be renamed or invented.

For private repos, nothing is read except framework names from the manifest
(package.json, pubspec.yaml and so on). That way "Flutter" can show up as
a skill without any private code being stored.

What it costs

The free tier is a hosted portfolio at forkfolio.dev/your-github-login with
nightly sync, the assistant and three designs. A one-time $19 (a launch
price, normally $29) unlocks all 21 designs and a custom domain. There's no
subscription, because a portfolio isn't something people want to rent.

About 160 developers have made one since July. Some live examples are on
the showcase.

What I'd like to know from you

What would you want a developer portfolio to show that your GitHub profile
can't?


I wrote this with help from an AI assistant; the product, the code
decisions and the numbers are mine.

Top comments (0)