Building My Developer Portfolio with Next.js, MDX, S3 & CloudFront
When I decided to rebuild my personal portfolio, I wanted to create a modern, scalable, and maintainable website that could showcase my projects and blog posts effectively. I chose Next.js for its powerful features and flexibility, MDX for content management, and AWS S3 & CloudFront for hosting.
In this article, I'll walk you through the architecture, hosting setup, and CI/CD pipeline I implemented for my portfolio.
Why Next.js?
I choose Next.js because it gives me Static Site Generation (SSG) and SEO optimization out of the box. For a portfolio and blog, SSG is perfect. Most content doesn't change per request, so generating static HTML at build time gives maximum performance. Next.js also has great support for MDX, which allows me to write my blog posts in Markdown with embedded React components.
Project Structure
My project is structured as follows:
luisv-dev/
├── app/
│ ├── blog/
│ │ ├── [slug]/
│ │ │ └── page.tsx
│ │ └── page.tsx
│ ├── mdx-component.tsx
│ └── page.tsx
├── content/
│ └── blog/
│ └── building-my-portfolio.mdx
├── components/
├── lib/
│ └── posts.ts- app/ - Used for UI and routing
- content/posts/ - All MDX blog posts
- lib/posts.ts - Utilities to read MDX files
Using MDX for the Blog
I store all my blog posts as MDX files in the content/blog/ directory. Using MDX allows me to write rich content with Markdown syntax and also include React components when needed, making it easy to create rich content. It also allows me to have a Git-based workflow for writing and editing blog posts.
Example MDX Post:
---
title: 'How I Built My Portfolio'
description: 'Architecture, hosting and CI/CD of my personal portfolio'
date: '2026-02-16'
tags: ['nextjs', 'architecture']
published: true
---
# Building My Portfolio
This is my article.
<AnyCustomComponent />To load posts I used:
gray-matterto parse the frontmatter metadatanext-mdx-remoteto render the MDX content- File system APIs to read the MDX files This setup allows me to easily add new blog posts by simply creating new MDX files in the content/blog/ directory. Since the site is statically generated, everything compiles into static HTML during the build process, ensuring fast load times.
S3 Hosting & CloudFront
For hosting, I chose AWS S3 to store the static files generated by Next.js and CloudFront as a CDN to serve the content globally with low latency. I configured my Next.js build to output the static files to a local directory, which I then upload to S3 using the AWS CLI in my CI/CD pipeline. CloudFront is set up to point to my S3 bucket, and I also configured a custom domain with SSL for secure access. Here's a simple diagram of the architecture:
User -> CloudFront -> S3 (Next.js Static Files)CloudFront handles:
- HTTPS (via ACM)
- Custom domain
- Global caching
- Performance optimization
Why not just use S3 website hosting?
- CloudFront gives edge caching
- Better security
- Custom domain with SSL
- Lower latency worldwide
Now my portfolio can load globally in milliseconds
Why not Vercel or Netlify?
Vercel or Netlify would have been easier to set up, but I wanted:
- Full infrastructure control
- Practice AWS skills
- Custom CI/CD pipeline
More than anything this project was a learning experience for me to understand how to build and deploy a modern web application from scratch using AWS services.
CI/CD Pipeline
Since manually uploading builds to S3 is tedious, I set up a CI/CD pipeline using GitHub Actions to automate the build and deployment process.
Here's a high-level overview of the pipeline
Every time I push to the main branch, the following steps are executed:
- Install dependencies
- Build project
- Deploy /out
- Invalidate CloudFront cache
Doing this ensures that every change I make to the codebase is automatically reflected on the live site without any manual intervention in just minutes.
What's Next?
This portfolio setup is just the beginning. I plan to add more features like:
Image Optimization Pipeline
Right now I manually optimize images before uploading them to S3. I want to build an AWS thumbnail generator using Lambda + S3 triggers so every uploaded image automatically generates:
- Blog friendly sizes
- SEO-optimized thumbnails
- WebP versions
Internazionalization (i18n)
Right now my portfolio is only in English, but I want to add support for multiple languages in the future. Next.js has built-in i18n support, so I plan to leverage that to make my content accessible to a wider audience.
As a developer based in Mexico working with global technologies, it makes sense for the portfolio to reflect that dual perspective.
Technical Writing Consistency
One of my biggest long-term goals is to maintain a consistent publishing schedule for my blog. I'm planning on using this portfolio as:
- A place to share my learnings and experiences in software development
- A way to document architecture decisions and best practices}
- A public journal of my growth as a developer