How to show the projects you've shipped on your GitHub profile README
Your GitHub profile is one of the few pages on the internet where people go specifically to find out what you have built, and for most makers it answers the question badly. The pinned repositories show code, the contribution graph shows activity, and the actual products, the things with users and a URL, are nowhere on it. This covers how to fix that with a profile README: where it lives, what GitHub will and will not render, a few layouts that work, and how to stop the list going stale.
By Utkarsh Kushwaha · Published
Where a profile README lives
GitHub shows a README at the top of your profile when you have a public repository with exactly the same name as your username, containing a README.md at its root. If your username is janedoe, the repository is janedoe/janedoe. GitHub recognises the name as you create it and says so on the new-repository form.
The repository has to be public, and the file has to be in the root of the default branch. Everything else about it is an ordinary repository: you can edit the README in the browser, commit from your machine, or update it from a GitHub Action.
What GitHub renders, and what it quietly removes
A README is GitHub-flavoured Markdown with a sanitised subset of HTML allowed inside it. Tables, links, images, headings, <details> blocks and simple attributes such as width and align survive. Script tags, style tags, inline style attributes and anything interactive are removed, without an error message.
Images are the other thing to understand. GitHub does not load an image straight from your server; it fetches it through its own image proxy, Camo, and serves the copy. That keeps visitors' IP addresses private, and it has two consequences worth knowing up front: the image has to be reachable on a public URL, and GitHub may keep showing a cached copy for a while after you change it.
Put together, this is why every 'widget' you have seen on a profile, the stats cards, the streak counters, the language charts, is an image. Somebody's server draws a picture on each request, and the README embeds its URL. There is no other way to put anything dynamic on the page.
What belongs in the first screen
Most visitors to a profile read a few lines and decide. Spend those lines on the two questions they arrived with: who is this, and what have they made? One sentence for the first. For the second, the products themselves, each linked to where it runs, not to its repository.
Keep the rest below the fold or leave it out. A long list of technology logos tells a visitor what you have used; your shipped work already tells them that, and shows it working. Visitor counters and quote-of-the-day images cost load time and say nothing about you.
A plain markdown list, which is the version to start with
The simplest layout is also the most robust: one line per product, the name linked to the live site, and what it does in the words a user would use. It renders everywhere, including GitHub's mobile app, and anyone can edit it in thirty seconds.
Hi, I'm Jane. I build small tools for people who ship.
### Things I've shipped
- **[Tiny Invoice](https://tinyinvoice.app)**: invoices for freelancers, in one screen
- **[Quiet Hours](https://quiethours.dev)**: a focus timer that mutes Slack for you
- **[Palette Pal](https://palettepal.io)**: colour palettes from any screenshotA table with icons, when you want it to look like a portfolio
An HTML table is allowed in a README and gives you an icon column, which makes a list of products recognisable at a glance. Use each product's own icon, served from its own site, and set the width attribute rather than relying on the file's size, because the style attribute is stripped.
Leave the alt text empty on a decorative icon that sits next to the product's name, so a screen reader does not announce every name twice.
<table>
<tr>
<td><img src="https://tinyinvoice.app/icon.png" width="32" alt=""></td>
<td><a href="https://tinyinvoice.app"><b>Tiny Invoice</b></a><br>Invoices for freelancers, in one screen</td>
</tr>
<tr>
<td><img src="https://quiethours.dev/icon.png" width="32" alt=""></td>
<td><a href="https://quiethours.dev"><b>Quiet Hours</b></a><br>A focus timer that mutes Slack for you</td>
</tr>
</table>Badges and dark mode
Small link badges are a compact way to add your site, your newsletter or your X account. Shields.io draws them from the URL alone, so a static one needs no setup: the path is label, message and colour.
A profile is read in both of GitHub's themes, and an image with a white background glares on the dark one. The <picture> element with a prefers-color-scheme media query is supported in READMEs and lets you serve a different image to each theme.
[](https://janedoe.dev)<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://janedoe.dev/card-dark.png">
<img alt="What I've shipped" src="https://janedoe.dev/card-light.png">
</picture>Keeping it current, which is where most profiles fail
A hand-written list is accurate the day you write it. The trouble is that a profile README is one more place to update on launch day, alongside your personal site, your link-in-bio page and the footer of every other product, and it is usually the one that gets forgotten. A year later it lists two projects out of five and one of them is dead.
The fix is the same one the stats cards use: make the list an image drawn from data you already maintain, so updating the source updates the README. You can build that yourself with a small serverless function that renders an SVG, or regenerate the README from a GitHub Action on a schedule.
Make Taksh does the first of those for the products you list in it. The same list that feeds the badge on your own sites can be embedded as an image, either a small 'Made by' pill or a card with every app and its one-line description, linked to your maker page. Editing the list in the dashboard updates the image; there is nothing to commit.
[](https://maketaksh.com/u/janedoe)When an image will not update
If you change an image and the profile still shows the old one, it is almost always Camo's cache rather than your server. Open the profile, copy the image address (it starts with camo.githubusercontent.com), and send it a PURGE request. GitHub documents this as the way to make it fetch a fresh copy.
If it still does not change, check the image's own URL directly. A server that sends long cache headers will be taken at its word by the proxy, so an image meant to change should be served with a short max-age.
curl -X PURGE https://camo.githubusercontent.com/<the-rest-of-the-image-address>Questions people ask about this
Can I use JavaScript in a GitHub profile README?
No. GitHub removes script tags, inline event handlers, style tags and style attributes from every README, silently. Anything that looks dynamic on a profile is an image generated by a server each time it is requested.
Do links in my GitHub README help my site's SEO?
Not directly. GitHub marks links in user-written content as nofollow, so they pass no ranking signal. Their value is the visits: a developer who reads your profile and clicks through to a product is worth more than the link would be.
Why doesn't my GitHub profile README show up?
Check three things: the repository name matches your username exactly, the repository is public, and README.md sits at the root of the default branch. If all three are right, it appears at the top of your profile.
Should I pin repositories or list products in the README?
Both, for different readers. Pinned repositories are for people who want to read your code. The README is the place to list products by what they do, linked to where they run, for people who want to see what you have made.
Can I put a Make Taksh badge on my GitHub profile?
Yes, as an image. GitHub runs no scripts, so the README version is an SVG in your badge's colours: a small pill or a card listing your apps, linked to your maker page. The line to paste is in the Install panel of your dashboard once your badge is published.
Where Make Taksh fits
Make Taksh is one line of code you paste into each site you own. It renders a small badge in the corner that lists everything you have shipped, reading from one hosted list, so adding your next project is one edit and every site you have already installed it on picks it up within minutes. It is under 8 KB, renders in a shadow root so it cannot touch your CSS, sets no cookies, and draws nothing at all if it fails to load.