<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Wiktor Małyska</title>
    <description>The latest articles on DEV Community by Wiktor Małyska (@wiktormalyska).</description>
    <link>https://dev.to/wiktormalyska</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3838408%2Fe021ffb0-c28c-4737-a5ce-a769ecae79be.jpeg</url>
      <title>DEV Community: Wiktor Małyska</title>
      <link>https://dev.to/wiktormalyska</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/wiktormalyska"/>
    <language>en</language>
    <item>
      <title>Stop Hardcoding Your Portfolio Projects. I Built an API to Turn GitHub into a Headless CMS</title>
      <dc:creator>Wiktor Małyska</dc:creator>
      <pubDate>Sun, 22 Mar 2026 13:27:32 +0000</pubDate>
      <link>https://dev.to/wiktormalyska/stop-hardcoding-your-portfolio-projects-i-built-an-api-to-turn-github-into-a-headless-cms-4n3k</link>
      <guid>https://dev.to/wiktormalyska/stop-hardcoding-your-portfolio-projects-i-built-an-api-to-turn-github-into-a-headless-cms-4n3k</guid>
      <description>&lt;p&gt;Every time I finished a new side project, I faced the exact same annoying routine:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open my portfolio repository.&lt;/li&gt;
&lt;li&gt;Find the &lt;code&gt;projects.json&lt;/code&gt; or hardcoded array.&lt;/li&gt;
&lt;li&gt;Manually type in the new project name, description, and tech stack.&lt;/li&gt;
&lt;li&gt;Download a screenshot, put it in the &lt;code&gt;public&lt;/code&gt; folder, and link it.&lt;/li&gt;
&lt;li&gt;Push changes and wait for the deployment.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;As developers, we automate everything, yet we still update our portfolios like it's 2010. I got tired of this, so I built a solution: &lt;strong&gt;PortfolioAPI&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is PortfolioAPI?
&lt;/h2&gt;

&lt;p&gt;It’s a simple tool that turns your GitHub repositories into a Headless CMS for your portfolio. Instead of manually updating your frontend code, your portfolio fetches data directly from your GitHub repos via one fast API call.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Live Link:&lt;/strong&gt; &lt;a href="https://portfolioapi.wiktormalyska.ovh/" rel="noopener noreferrer"&gt;PortfolioAPI&lt;/a&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  How it works (It takes 2 minutes)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Drop a &lt;code&gt;meta.json&lt;/code&gt; in your repo&lt;/strong&gt;&lt;br&gt;
You just create a &lt;code&gt;meta.json&lt;/code&gt; file in the root of any public GitHub repository you want to showcase.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"My Awesome Project"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"A short description shown on the portfolio page."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"imageUrl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"[https://raw.githubusercontent.com/your-username/your-repo/main/assets/screenshot.png](https://raw.githubusercontent.com/your-username/your-repo/main/assets/screenshot.png)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"websiteUrl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"[https://my-project.example.com](https://my-project.example.com)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"technologies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"React"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"TypeScript"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"TailwindCSS"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 2: Fetch the data in your frontend&lt;/strong&gt;&lt;br&gt;
Make a single GET request using your API key. The API scans your GitHub, finds all repos with a &lt;code&gt;meta.json&lt;/code&gt;, and returns a clean, structured array of your projects.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fetchProjects&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[https://api.portfolioapi.wiktormalyska.ovh/projects](https://api.portfolioapi.wiktormalyska.ovh/projects)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;X-API-KEY&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;your_api_key_here&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Boom! Ready to map over in React/Vue/Svelte&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why did I build it this way?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Zero Database Needed:&lt;/strong&gt; Your code lives on GitHub anyway, why not keep its metadata there too?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Always Up to Date:&lt;/strong&gt; Update the &lt;code&gt;meta.json&lt;/code&gt; in your project repo, and your portfolio updates instantly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Blazing Fast:&lt;/strong&gt; I implemented server-side caching so the GitHub data is delivered in milliseconds. No unnecessary noise.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tech Agnostic:&lt;/strong&gt; It doesn't matter if your portfolio is built in React, Vue, Next.js, or vanilla HTML. It’s just a standard REST API.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What's next?
&lt;/h2&gt;

&lt;p&gt;Right now, the API handles reading GitHub portfolios perfectly. I'm currently working on adding a dedicated Node.js package and an email contact form endpoint to make it an all-in-one backend for developer portfolios.&lt;/p&gt;

&lt;p&gt;I’m an indie developer trying to build tools that actually save time. I’d love to hear your feedback. What do you think about managing portfolio content directly from GitHub repos? &lt;/p&gt;

&lt;p&gt;Let me know in the comments! 👇&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Psst... with code FREETRIAL you can get first month for free! (for first 10 customers)&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>productivity</category>
      <category>github</category>
    </item>
  </channel>
</rss>
