A modern personal website framework built with Next.js 15, React 19, TypeScript, Material UI, and PostgreSQL. DevHolm uses a layered architecture that separates the framework engine from your personalizations โ making upgrades safe and non-destructive.
๐ Live Example: chrishacia.com ๐ฌ Discord: Join the Community
DevHolm follows a layered framework model:
src/core/ โ Framework engine (updated by DevHolm, never touch directly)
src/user/ โ Your customizations (content, extensions, view overrides)
src/app/ โ Next.js routing (thin wrappers only)
devholm.config.ts โ Your single configuration file
See docs/architecture.md for the full picture.
pnpm install
cp .env.example .env # fill in DB + auth secrets
pnpm db:setup
pnpm seed:admin
pnpm devOptional demo content:
pnpm db:seed:demoSee docs/getting-started.md for the full quick start and docs/developer-guide.md for the framework workflow.
Edit devholm.config.ts and the files in src/user/:
// devholm.config.ts
const config: DevHolmConfig = {
content: { about, home, now }, // Your narrative content
slots: { 'home.hero.below': MyBanner }, // Inject components into views
views: { about: () => import('./src/user/views/about/AboutView') }, // Eject & override
extensions: { admin: myExtensions }, // Add admin sidebar items
};pnpm devholm status # See what's ejected and extended
pnpm devholm eject about # Override the About view locally
pnpm devholm new:extension telemetry # Scaffold admin extension
pnpm devholm new:migration add_subscribers # Create user DB migration
pnpm devholm list:slots # See all injection pointsSee docs/cli.md.
| Doc | Description |
|---|---|
| Getting Started | Installation and first setup |
| Developer Guide | Local workflow, boundaries, seeds, and extension rules |
| Architecture | Layer model, directory structure, aliases |
| Configuration | Full devholm.config.ts reference |
| Extensions | Slots, admin extensions, view overrides, migrations |
| CLI | All CLI commands |
| Upgrading | How to update DevHolm safely |
| Deployment | Server setup and production deployment |
| GitHub Secrets | Required repository secrets for CI/CD deploys |
- Blog System โ Markdown support, tags, series, reading time, RSS feed
- Projects Portfolio โ Showcase your work with images and links
- Resume/CV โ Display your professional experience
- Now Page โ Share what you're currently working on
- Uses Page โ Document your tools and setup
- Post Management โ Create, edit, and schedule blog posts
- Media Library โ Upload and manage images with automatic optimization
- Contact Inbox โ View and manage form submissions
- Analytics Dashboard โ Privacy-focused page view tracking
- Site Settings โ Configure your site from the admin panel
- Light/Dark Mode โ System preference detection + manual toggle
- Fully Responsive โ Looks great on all devices
- Accessible โ WCAG compliant components
- SEO Optimized โ Dynamic OG images, sitemap, structured data
- Docker Ready โ Production-ready Dockerfile and compose setup
- CI/CD Pipeline โ GitHub Actions for testing, building, and deployment
- E2E Testing โ Playwright test suite included
- Hot Reload โ Fast refresh during development
- Node.js 20+
- pnpm 9+
- PostgreSQL 15+ (local or Docker)
git clone https://github.com/chrishacia/devholm.git my-site
cd my-site
pnpm installOption A: Using Docker (recommended for development)
# Start PostgreSQL in Docker
docker run --name devholm-postgres -e POSTGRES_PASSWORD=postgres -e POSTGRES_DB=mysite_dev -p 5432:5432 -d postgres:16
# Verify it's running
docker psOption B: Local PostgreSQL
# macOS (Homebrew)
brew install postgresql@16
brew services start postgresql@16
# Create database
createdb mysite_devOption C: Using existing PostgreSQL
Just update the database credentials in your .env file (see next step).
cp .env.example .envEdit .env with your configuration. The most important settings are:
# Database (required)
DATABASE_HOST=localhost
DATABASE_PORT=5432
DATABASE_NAME=mysite_dev
DATABASE_USER=postgres
DATABASE_PASSWORD=postgres
# Or use a connection URL instead:
# DATABASE_URL=postgresql://postgres:postgres@localhost:5432/mysite_dev
# Admin credentials (used when seeding)
ADMIN_EMAIL=admin@localhost.com
ADMIN_PASSWORD=your-secure-password
# Authentication secret (any string for dev, generate for production)
AUTH_SECRET=dev_secret_change_in_production
AUTH_URL=http://localhost:3000๐ Note: See
.env.examplefor all available configuration options including social links, file upload settings, and rate limiting.
# Create database tables
pnpm db:migrate
# Create your admin user (uses ADMIN_EMAIL and ADMIN_PASSWORD from .env)
pnpm seed:adminpnpm devVisit http://localhost:3000 ๐
Admin panel: http://localhost:3000/admin
Login with the ADMIN_EMAIL and ADMIN_PASSWORD from your .env file.
Database connection errors:
- Verify PostgreSQL is running:
pg_isreadyordocker ps - Check credentials in
.envmatch your PostgreSQL setup - Ensure the database exists:
psql -lto list databases
Migration errors:
- Check for pending migrations:
pnpm db:migrate - Reset and start fresh:
pnpm db:migrate:rollbackthenpnpm db:migrate
Admin user not working:
- Re-run the seed:
pnpm seed:admin - Check the email/password in your
.envfile
โโโ src/
โ โโโ app/ # Next.js App Router pages
โ โ โโโ admin/ # Admin dashboard pages
โ โ โโโ api/ # API routes
โ โ โโโ blog/ # Blog pages
โ โ โโโ about/ # About page
โ โ โโโ projects/ # Projects portfolio
โ โ โโโ resume/ # Resume/CV
โ โ โโโ ... # Other pages
โ โโโ components/ # React components
โ โ โโโ admin/ # Admin-specific components
โ โ โโโ common/ # Shared components
โ โ โโโ layout/ # Layout components
โ โ โโโ seo/ # SEO components
โ โโโ config/ # Site configuration
โ โโโ db/ # Database layer
โ โ โโโ migrations/ # Knex migrations
โ โ โโโ seeds/ # Seed files
โ โโโ hooks/ # Custom React hooks
โ โโโ lib/ # Utility functions
โ โโโ theme/ # MUI theme configuration
โ โโโ types/ # TypeScript types
โโโ public/ # Static assets
โโโ e2e/ # Playwright E2E tests
โโโ scripts/ # Utility scripts
โโโ docs/ # Documentation
| Command | Description |
|---|---|
pnpm dev |
Start development server |
pnpm build |
Build for production |
pnpm start |
Start production server |
pnpm lint |
Run ESLint |
pnpm lint:fix |
Fix ESLint errors |
pnpm typecheck |
Run TypeScript checks |
pnpm test |
Run unit tests (Vitest) |
pnpm test:watch |
Run tests in watch mode |
pnpm test:e2e |
Run E2E tests (Playwright) |
pnpm db:migrate |
Run database migrations |
pnpm db:migrate:rollback |
Rollback last migration |
pnpm db:seed |
Run all seed files |
pnpm seed:admin |
Create initial admin user |
This project uses a centralized environment configuration system:
.env.example # Template with all available variables (check into git)
.env # Your local configuration (NOT in git)
src/config/env.ts # TypeScript config that reads from process.env
src/config/site.ts # Static site configuration
- Copy
.env.exampleto.envfor local development - The app reads environment variables via
src/config/env.ts - All configs have sensible defaults for development
- Production uses GitHub Secrets โ Docker environment variables
| Variable | Description | Default |
|---|---|---|
NEXT_PUBLIC_APP_URL |
Public site URL | http://localhost:3000 |
NEXT_PUBLIC_SITE_NAME |
Site name for UI/SEO | My Site |
NEXT_PUBLIC_SITE_DESCRIPTION |
Site description for SEO | A personal website |
NEXT_PUBLIC_AUTHOR_NAME |
Author name | Your Name |
NEXT_PUBLIC_AUTHOR_EMAIL |
Author email | you@example.com |
DATABASE_URL |
Full database connection URL | - |
DATABASE_HOST |
Database host | localhost |
DATABASE_PORT |
Database port | 5432 |
DATABASE_NAME |
Database name | mysite |
DATABASE_USER |
Database user | postgres |
DATABASE_PASSWORD |
Database password | - |
AUTH_SECRET |
NextAuth secret | dev-secret... |
AUTH_URL |
Auth callback URL | http://localhost:3000 |
ADMIN_EMAIL |
Admin email for seeding | admin@localhost.com |
ADMIN_PASSWORD |
Admin password for seeding | changeme123 |
๐ See
.env.examplefor the complete list including social links, upload settings, and rate limiting options.
All configuration is done via environment variables, making it easy to personalize without touching code:
# Branding
NEXT_PUBLIC_SITE_NAME="My Portfolio"
NEXT_PUBLIC_AUTHOR_NAME="Jane Developer"
NEXT_PUBLIC_AUTHOR_EMAIL=jane@example.com
# Social Links (leave empty to hide)
NEXT_PUBLIC_SOCIAL_TWITTER=janedev
NEXT_PUBLIC_SOCIAL_GITHUB=janedev
NEXT_PUBLIC_SOCIAL_LINKEDIN=janedevCustomize colors and styles in src/theme/theme.ts:
// Light theme primary color
primary: {
main: '#22C55E', // Change to your brand color
},See THEMING.md for detailed theming documentation.
Edit the page content in:
src/app/about/AboutPageClient.tsxโ Your bio and storysrc/app/now/NowPageClient.tsxโ What you're working onsrc/app/uses/UsesPageClient.tsxโ Your tools and setup
Seed your own data by editing:
src/db/seeds/seed-resume-example.tsโ Your work experiencesrc/db/seeds/seed-projects-example.tsโ Your projects
The project includes a production-ready Docker setup:
# Build the image
docker build -t devholm .
# Run with docker-compose
docker-compose up -dThe included workflow automatically:
- Runs linting and type checks
- Runs unit and E2E tests
- Builds Docker image
- Deploys to your server
๐ก Note: GitHub Actions are free for public repositories. If you fork/clone this repo and make it private, you'll be charged for Actions minutes. See GitHub's pricing for details.
Set these GitHub Secrets (13 required):
| Secret | Description |
|---|---|
PROJECT_NAME |
Unique identifier for Docker (e.g., mysite) |
SITE_URL |
Production URL (e.g., https://yoursite.com) |
SITE_NAME |
Display name for the site |
DEPLOY_HOST |
Server hostname/IP |
DEPLOY_USER |
SSH username |
DEPLOY_KEY |
SSH private key |
DEPLOY_PATH |
Deployment directory |
POSTGRES_USER |
Database username |
POSTGRES_PASSWORD |
Database password |
POSTGRES_DB |
Database name |
NEXTAUTH_SECRET |
Auth encryption key |
ADMIN_EMAIL |
Initial admin email |
ADMIN_PASSWORD |
Initial admin password |
Optional: APP_PORT (default: 3000), CSRF_SECRET, DOCKERHUB_USERNAME, DOCKERHUB_TOKEN
๐ See DEPLOYMENT.md and GITHUB_SECRETS.md for detailed guides.
While optimized for self-hosting, you can also deploy to:
- Vercel โ Works out of the box (requires external PostgreSQL)
- Railway โ Full-stack deployment with managed PostgreSQL
- Render โ Free tier available
DevHolm includes a privacy-focused analytics system:
- No cookies required
- No personal data stored
- GDPR compliant
- View stats in the admin dashboard
To disable, remove <PageViewTracker /> from src/app/layout.tsx.
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing) - Open a Pull Request
This project is licensed under the MIT License โ see the LICENSE file for details.
Built with these amazing open-source projects:
Made with โค๏ธ by Chris Hacia