Combines Next.js, React, TypeScript, Theme UI, and MDX, with article front matter validated by zod
ahurle-dev — Next.js Portfolio Template
By fracture91
A personal website and developer blog template built with Next.js, React, TypeScript, Theme UI, and MDX. It is a heavily modified fork of Devii and is MIT licensed.
Explore the design
Compare the page layouts and mobile experience. Open any screenshot for a closer look.
Actual screenshot captured by the server browser.
All pages & views 3
Screenshots show visual appearance; interactive behavior may differ.
What stands out
A quick read of the recorded project description.
Automatically extracts summaries, tables of contents, and reading times from blog posts, with syntax highlighting for code blocks
Pages use static generation, the site still works with client-side JS disabled, and images are optimized via next/image
Built-in integration points for GoatCounter analytics, Sentry error reporting, and a TinyLetter subscription form
Provides ESLint, Prettier, Jest, and GitHub Actions CI, with next-page-tester smoke tests for pages
Template Details
This is a Next.js template for building a personal website and developer blog. The repository states that it powers the ahurle.dev site and is a heavily modified fork of the Devii project. The stack combines Next.js, React, TypeScript, Theme UI, and MDX: articles and other pages are written in MDX, with front matter exported as JS objects and validated by zod.
On the content side, the template extracts summaries, tables of contents, and reading times from each blog post, applies syntax highlighting to code blocks, and supports dark mode provided by Theme UI. Pages use static generation, and the site still works with client-side JS disabled; images are handled through next/image.
Supporting features include GoatCounter analytics, Sentry client-side error reporting, a TinyLetter subscription form, RSS and sitemap, plus ESLint, Prettier, Jest, and GitHub Actions CI configuration; pages also have smoke tests based on next-page-tester.
When using it as a fork, you need to change the name and domain in helpers/globals.ts, update the URL in next-sitemap.js, and replace the account identifiers for GoatCounter, Sentry, and TinyLetter; static assets such as the avatar, favicon, and logo are in the public directory, while body content is concentrated in the pages directory. The repository notes that deployment is easiest on Vercel, that it depends on some VERCEL_* environment variables, and that next/image requires server-side image transformation.
Is it right for your project?
Use Cases
- Building a personal developer blog and publishing MDX articles
- Using it as the basis for a personal portfolio site by replacing the avatar, logo, and page copy
- Forking it into your own site and replacing the analytics, error reporting, and subscription service accounts
Suitable For
- Developers familiar with Next.js and React who are willing to configure external services themselves
- Personal site authors who need an MDX writing workflow and a statically generated blog
- Users who want to start from MIT-licensed code and adjust the styling and content themselves
Getting started & customization
Use these recorded setup notes alongside the repository instructions for your chosen version.
- 1
Requires nvm and yarn; after cloning the repository, run nvm use, yarn install, and yarn dev, with the local address at http://localhost:3000
- 2
Modify constants such as the name and domain in helpers/globals.ts, and update the URL in next-sitemap.js accordingly
- 3
Replace the account identifiers for GoatCounter, Sentry, and TinyLetter; set them to null to disable the corresponding features when not needed
- 4
Replace the avatar, favicon, and logo in the public directory, and remove unneeded static files; body content is in the pages directory
- 5
After changes, run yarn test to update snapshots and confirm that yarn lint passes
License & source material
Usage conditions & limitations
Free to use · keep license noticeThis entry covers the free version in the public repository under the MIT license; the free scope is the code of that version and does not mean that external services or third-party assets are free.
Must comply with when using
- You may use, modify, commercially use, and distribute the code of this version for free.
- When distributing copies or substantial portions of the code, retain the original author's copyright notice and the full MIT license notice.
- The code is provided as is; warranties and limitations of liability are governed by the original license and applicable law.
Additional costs & items to verify
- The author requests (not required by the license) that fork users adjust the styling to make it their own site and delete content such as the original author's blog posts; the MIT license itself does not enforce this.
- Using GoatCounter site analytics requires registering your own account and replacing goatCounterId; set it to null to disable when not needed.
- Using Sentry client-side error reporting requires registering your own account and replacing sentryPublicKey and sentryDsn; set them to null when not needed.
- The TinyLetter subscription form requires registering your own account and replacing tinyLetterUsername, or setting it to null to disable the form.
- Deployment is recommended on Vercel with an account; the project depends on some VERCEL_* environment variables, and next/image requires server-side image transformation.
- It depends on VERCEL_* environment variables, and next/image image optimization requires a server, so pure static hosting may not be able to use that image optimization feature.
- Some actions in GitHub Actions (especially bundlewatch) may require additional separate configuration.
- config/imageSizeLoader.js is based on third-party code under the Apache License 2.0, and using it requires complying with that license's attribution and other conditions.
- Demo images, fonts, icons, and other third-party assets must be checked against their respective licenses and cannot be judged solely by the code's MIT license.
- External services such as domains, hosting, databases, payments, or AI may incur separate charges.
View Original Text Basis
Permission is hereby granted, free of charge
Original License Text
All I ask is that you style it a little differently - make it "yours". And remove my blog posts and stuff, of course.
Original README
If you want to use GoatCounter for site analytics, [sign up for an account]
Original README
You can use Sentry to catch unhandled exceptions on the client side of your app. [Sign up for an account]
Original README
The site contains newsletter signup forms thanks to TinyLetter. [Sign up for an account]
Original README
The easiest way to deploy this app is through Vercel. [Sign up for an account]
Original README
Note that I depend on some `VERCEL_*` environment variables, and [`next/image`](https://nextjs.org/docs/basic-features/image-optimization?utm_source=ahurle-dev) requires a server to transform image URLs.
Original README
You may also need to do some separate setup for the specific actions I'm using - especially [bundlewatch]
Original README
https://github.com/fracture91/ahurle-dev/blob/master/LICENSEhttps://github.com/fracture91/ahurle-dev/blob/master/README.md[imageSizeLoader.js](./config/imageSizeLoader.js) based on [image-size-loader]
Original README
Compiled by DeepSeek based on repository license and README ·2026-10-02. Results only cover the materials read; dependencies, images, fonts, and subsequent term changes are subject to their respective original texts.
Project checks & description sources
Template Information
- Source platforms
- GitHub
- Documentation and maintenance reference score
- Partly documented · 73 / 100
- Technologies
- Next.js · React
- Website type
- Portfolio · Blog · Starter
How this score is calculated
Our heuristic uses license records (up to 30), a demo link (12), a preview (10), stars (15), recorded maintenance (15), description completeness (8), feature records (5) and classification data (5). It is not a code, security or performance test, or a Google score. A link does not establish tested functionality.
What to verify for this project
- Repository update recorded
- 2022-12-07
- Screenshot last checked
- 2026-10-02
A demo link is listed. Check it with your own content and viewport sizes; its presence does not confirm that forms, authentication or payments work.
The catalog identifies Next.js as the primary stack. Check the actual dependency manifest and lockfile for versions and hosting requirements. These notes use recorded metadata, not a code audit or a deployment test.
Use a selection guide →How this description was prepared
AI-assisted description based on catalog records and repository material. Repository authors are not automatically the reviewers of this description.
Automatically checked against source and license rules; no manual editorial review.
Inspect the recorded source material
SHA-256: 79a4fb5e7daf91346c73b215e9914b9147cd066712aefc4d914eab9069dff4af
2026-10-02T20:06:06.593Z
Source file / repository# ahurle-dev
Powers the
[ahurle.dev](https://ahurle.dev/?utm_source=github)
website and developer blog. Heavily modified fork of
[Devii](https://github.com/colinhacks/devii?utm_source=ahurle-dev).
[I wrote a blog post about this project](https://ahurle.dev/blog/overengineering-a-nextjs-dev-blog?utm_source=github)
if you want some more context on why it exists.
Feel free to fork this repo for your own website! I know how annoying it is to get everything working nicely if you were to start from scratch instead. All I ask is that you style it a little differently - make it "yours". And remove my blog posts and stuff, of course. It would also be nice if you linked back to me, but it's all MIT licensed so... 🤷♂️
## Features
- Modern Next.js, React, TypeScript stack
- Author blog posts and other pages in [MDX](https://mdxjs.com/?utm_source=ahurle-dev), export "front matter" as a JS object validated by [`zod`](https://github.com/colinhacks/zod?utm_source=ahurle-dev)
- Syntax highlighting for code blocks in your blog posts
- Dark mode support with [`theme-ui`](https://github.com/system-ui/theme-ui?utm_source=ahurle-dev)
- All pages get automatic smoke tests from [`next-page-tester`](https://github.com/toomuchdesign/next-page-tester/?utm_source=ahurle-dev)
- All pages use [static generation](https://nextjs.org/docs/basic-features/pages?utm_source=ahurle-dev#static-generation-recommended) and the site functions with client-side JS disabled
- Effortless image optimization with [`next/image`](https://nextjs.org/docs/api-reference/next/image?utm_source=ahurle-dev)
- Free analytics from [GoatCounter](https://www.goatcounter.com/?utm_source=ahurle-dev)
- Free hosting from [Vercel](https://vercel.com?utm_source=ahurle-dev)
- Free client-side exception reporting from [Sentry](https://sentry.io?utm_source=ahurle-dev)
- ESLint, Prettier, Jest, and a CI config for [Github Actions](https://github.com/features/actions?utm_source=ahurle-dev) - Free!
- Newsletter signup with [TinyLetter](https://tinyletter.com/?utm_source=ahurle-dev)
- Excerpt, Table of Contents, and Reading Time get extracted from each blog post
- SEO, a11y, RSS, sitemap, page speed are all in pretty good shape
## Getting started
- Install [nvm](https://github.com/nvm-sh/nvm#installing-and-updating)
and [yarn](https://yarnpkg.com/getting-started/install)
(perhaps [yvm](https://yvm.js.org/docs/overview) too).
- Clone/fork this repo and `cd` into it
```bash
nvm use # see .nvmrc
yarn install
yarn dev
```
You should now see my site running on http://localhost:3000
<details>
<summary>M1 Mac Special Instructions</summary>
I ran this on node 14.x for a while without problems. At some point it started exploding on `yarn install`. I was able to get around it like so:
```bash
nvm install v15.11.0
nvm use v15.*
vim package.json # change engines -> node to "15.x"
```
Note that vercel does not support node 15.x or higher yet. It will probably also work if you use Rosetta for Node 14 rather than trying to compile it natively for arm64.
</details>
<br/>
## CLI
- `yarn dev` - Starts the development server. Equivalent to `next dev`.
- `yarn build` - Creates an optimized, production build of your site. Equivalent to `next build`. Use `yarn start` to run this build locally.
- `ANALYZE=true yarn build` - Also opens webpack-bundle-analyzer output in your browser
- `yarn export` - Exports your site to static files. Equivalent to `next export`.
- `yarn lint` - Run eslint and prettier checks. Use `yarn lint:eslint` or `yarn lint:prettier` for specific checks
- `yarn test` - Run tests
## Creating Your Own Website As a Fork
There are a few basic things you'll want to change right away to make it "your" site:
### [helpers/globals.ts](./helpers/globals.ts)
The constants in this file are pretty self-explanatory. Change the name to match your name, the domain to match yours, etc.
### [next-sitemap.js](./next-sitemap.js)
I got lazy here and duplicated some config from `globals.ts` - change the URL to match your prodUrl, and add any exclusions for e.g. unpublished blog posts.
### GoatCounter
If you want to use GoatCounter for site analytics, [sign up for an account](https://www.goatcounter.com/signup?utm_source=ahurle-dev) and replace `goatCounterId` with your own. If you don't want to use it, you can set `goatCounterId` to null.
[`GoatCounterScript`](./components/GoatCounterScript.tsx) and [`GoatCounterPixel`](./components/GoatCounterPixel.tsx) contain some hardcoded checks to make sure you don't accidentally dump your data into my account in case you haven't read these instructions yet. Changing/Removing these is left as an exercise for the reader.
By default, analytics are only enabled in the prod environment, but you can test in dev by commenting out the prod checks.
### Sentry
You can use Sentry to catch unhandled exceptions on the client side of your app. [Sign up for an account](https://sentry.io/signup/?utm_source=ahurle-dev) and replace `sentryPublicKey` and `sentryDsn` with your own. If you don't want to use it, you can set either constant to null.
Like with `GoatCounterPixel`, there are some hardcoded checks in `SentryLoader` that you might want to remove.
By default, sentry only runs in prod and preview mode, but it can run in dev by commenting out the checks. Try calling `window.onerror("hello world")` to make Sentry log an error.
### TinyLetter
The site contains newsletter signup forms thanks to TinyLetter. [Sign up for an account](https://tinyletter.com/?utm_source=ahurle-dev) and replace `tinyLetterUsername` with your own, or set it to null to disable the forms.
### Snapshots
Once you've changed all this stuff, run `yarn test`. You'll probably have a bunch of failing snapshots that used to contain _my_ globals. Press `u` to update the snapshots to contain _your_ globals. Making sure `yarn lint` still passes is also a good idea.
### Github Actions
This project contains a [CI config](./.github/workflows/ci.yml) that should run whenever you open/update a PR or push to master. It's a good idea to make sure that's passing now. [Here's some documentation to get you started](https://docs.github.com/en/actions/quickstart?utm_source=ahurle-dev).
You may also need to do some separate setup for the specific actions I'm using - especially [bundlewatch](https://github.com/jackyef/bundlewatch-gh-action?utm_source=ahurle-dev) - but I don't remember the specifics 🤷♂️
### Vercel
The easiest way to deploy this app is through Vercel. [Sign up for an account](https://vercel.com/signup?utm_source=ahurle-dev) and you can have it deploy your repo with a few clicks. You should be able to visit your site at a `*.vercel.app` domain for now, and later you can point a domain at it like `ahurle.dev`. Remember to change `prodUrl` in `globals.ts` if your domain changes.
If you want to use something else then it's probably not very difficult to switch. Note that I depend on some `VERCEL_*` environment variables, and [`next/image`](https://nextjs.org/docs/basic-features/image-optimization?utm_source=ahurle-dev) requires a server to transform image URLs.
### Assets
- [me.jpg](./public/img/me.jpg): Change this to be an image of you, or delete it if you don't want one
- [favicon.ico](./public/favicon.ico),
[logo.png](./public/img/logo.png),
and [logo.svg](./public/img/logo.svg):
This is the favicon for your site. You'll want to replace these with images of your own creation.
- The rest of the non-SVG files in [/public](./public) can probably be deleted
### Content
Most of the text on the site lives in [/pages](./pages). If you aren't familiar with the concept of pages in Next.js, I recommend [reading the docs](https://nextjs.org/docs/routing/introduction?utm_source=ahurle-dev). You will probably also want to change the [Footer](./components/Footer.tsx) and [Header](./components/Header.tsx).
### Have fun!
The rest is up to you!
<br/>
## License
Most code © 2021 Andrew Hurle, [MIT License](./LICENSE)
Based on [Devii](https://devii.dev/?utm_source=ahurle-dev), © 2020 Colin McDonnell, [MIT License](https://github.com/colinhacks/devii/blob/31ffa9e1399acabd0f79f228dd19336864907165/LICENSE)
[imageSizeLoader.js](./config/imageSizeLoader.js) based on [image-size-loader](https://github.com/boopathi/image-size-loader), © 2015 Patrick Collins and Boopathi Rajaa, [Apache License 2.0](https://github.com/boopathi/image-size-loader/blob/bf1f3bc31c1a9ef579a957a77514ef665681848c/LICENSE)
[mdxDefaultLayout.js](./config/mdxDefaultLayout.js) based on [a file from silvenon.com](https://github.com/silvenon/silvenon.com/blob/3f1bfaad8ad4794cacd7623bff7627ce5e21ceda/etc/remark-mdx-default-layout.js), © 2020 Matija Marohnić <[email protected]> (silvenon.com), [MIT License](https://github.com/silvenon/silvenon.com/blob/3f1bfaad8ad4794cacd7623bff7627ce5e21ceda/license)
[mdxImageMetadata.js](./config/mdxImageMetadata.js) based on [a file from kylepfromer.com](https://github.com/kpfromer/portfolio/blob/ba194a9a82c176f7e58f912572d6a0ff8e8bad4c/plugins/image-metadata.ts), © 2019 Kyle Pfromer, [MIT License](https://github.com/kpfromer/portfolio/blob/ba194a9a82c176f7e58f912572d6a0ff8e8bad4c/LICENSE)
[prismStyle.ts](./helpers/prismStyle.ts) based on [the darcula theme from react-syntax-highlighter](https://github.com/react-syntax-highlighter/react-syntax-highlighter/blob/efc3f7b7537d1729193b7a472067bcbe6cbecaf1/src/styles/prism/darcula.js), © 2019 Conor Hastings, [MIT License](https://github.com/react-syntax-highlighter/react-syntax-highlighter/blob/efc3f7b7537d1729193b7a472067bcbe6cbecaf1/LICENSE)
Explore similar templates
Compare previews and descriptions within the same stack and category.

Next.js SaaS Starter
The official Next.js SaaS starter template, integrating email/password authentication, Stripe Checkout subscriptions, a dashboard with user/team CRUD, basic Owner/Member RBAC, and activity logging.
Next.js · SaaS

Next.js Commerce
Vercel's officially maintained Next.js App Router ecommerce starter with deep Shopify integration, offering a complete product catalog, cart, and checkout flow. Core logic is modular for swapping backends, and community provider versions exist for BigCommerce, Medusa, and Saleor.
Next.js · E-commerce

Next-js-Boilerplate
A developer-first Next.js 16 starter with Tailwind CSS 4 and TypeScript, supporting both App Router and Page Router.
Next.js · Starter

tailwind-nextjs-starter-blog
A Next.js and Tailwind CSS blog starter template using Contentlayer for Markdown/MDX, with built-in SEO, code highlighting, and tags. It targets personal technical blogs and migration from Jekyll/Hugo to React, and supports one-click Vercel deployment.
Next.js · Blog

next-forge
next-forge is a Turborepo-based Next.js template maintained by Vercel, positioned as a starting point for SaaS products.
Next.js · Starter

SaaS-Boilerplate
SaaS-Boilerplate is an open-source SaaS starter template built with Next.js App Router, React 19, TypeScript, Tailwind CSS, and Shadcn UI.
Next.js · SaaS
