Building montreuil.dev: A Brutalist Developer Portfolio
How I built my developer portfolio using Astro, React, and MDX, featuring a brutalist design, modern development practices, and excellent performance
Building montreuil.dev
After years of building developer tools and platforms for others, I decided it was time to create a proper home for my own work. I wanted something that would reflect my focus on developer experience while being maintainable and performant. Here’s how it was built!
Design Philosophy
I chose a brutalist design approach for several reasons:
- Clarity of Purpose: Like the architectural style it’s named after, brutalist web design emphasizes function and raw materials—in this case, HTML, CSS, and typography.
- Developer Focus: The terminal-inspired aesthetic resonates with developers while remaining highly readable.
- Performance: Minimal design means minimal JavaScript and faster load times.
The design features:
- High contrast black/white theme
- Monospace typography (JetBrains Mono)
- Terminal-inspired UI elements
- Visible structural components
- Dark mode support
Technical Architecture
Core Stack
- Astro: Static site generation with partial hydration
- React: Interactive components
- TypeScript: End-to-end type safety
- Tailwind CSS: Utility-first styling
- MDX: Rich content with interactive components
Project Structure
  montreuil.dev/
  ├── src/
  │   ├── components/      # Reusable components
  │   │   ├── layout/     # Layout components
  │   │   ├── home/       # Home page components
  │   │   ├── projects/   # Project-related components
  │   │   ├── articles/   # Article-related components
  │   │   └── mdx/        # MDX-specific components
  │   ├── content/        # MDX content
  │   │   ├── projects/   # Project writeups
  │   │   └── articles/   # Blog posts
  │   ├── layouts/        # Page layouts
  │   ├── pages/         # Route components
  │   ├── styles/        # Global styles
  │   └── types/         # TypeScript types
Implementation Details
Type System
A robust type system was crucial for maintainability. The implementation includes:
- Generic type utilities for content collections
- Strict null checks and explicit return types
- Type-safe MDX content through Astro collections
- Proper component prop typing
Content Management
Content is managed through Astro’s collection system with:
- Type-safe frontmatter validation using Zod
- Automated slug generation
- Built-in content preprocessing
- Rich MDX support with component imports
Brutalist Layout
The core layout component embodies brutalist principles through:
- Terminal-inspired navigation with path-style links (/about,/projects)
- High contrast borders and structural elements
- Minimalist status bar showing location and availability
- System-aware dark mode with smooth transitions
- Visible grid system and structural elements
Developer Experience
ESLint Configuration
The ESLint setup focuses on maintainable, high-quality code through carefully selected rule sets:
Development Experience:
- TypeScript-specific rules with sensible defaults
- React and hooks best practices enforcement
- Accessibility (a11y) checks for components
- Import ordering and organization
Quality Controls:
- Enforced consistent code style
- Dead code elimination
- React performance patterns
- Type safety checks
Custom configurations per file type:
- .ts/- .tsxfiles for TypeScript code
- .astrofiles for Astro components
- .mdxfiles for content
- React component files
Automated Code Quality
Comprehensive scripts for linting and formatting:
{
  "scripts": {
    "lint": "npm-run-all --parallel lint:*",
    "lint:eslint": "eslint \"src/**/*.{ts,tsx,js,jsx,astro}\" --fix",
    "lint:prettier": "prettier --check \"src/**/*.{ts,tsx,js,jsx,astro,css,md,mdx,json}\"",
    "lint:types": "astro check --silent && tsc --noEmit",
    "lint:spell": "cspell \"**\" --no-progress",
    "format": "npm-run-all --sequential format:*",
    "format:prettier": "prettier --write \"src/**/*.{ts,tsx,js,jsx,astro,css,md,mdx,json}\"",
    "format:eslint": "eslint \"src/**/*.{ts,tsx,js,jsx,astro}\" --fix"
  }
}
Pre-commit Hooks
Using Husky and lint-staged for pre-commit quality checks:
module.exports = {
  // Type check staged TypeScript files
  '**/*.{ts,tsx}': () => 'pnpm astro check',
  
  // Lint and format staged files
  '**/*.{js,jsx,ts,tsx,astro}': ['eslint --fix', 'prettier --write'],
  
  // Format other files
  '**/*.{css,json,md,mdx,yaml,yml}': ['prettier --write'],
};
Performance Optimization
The site achieves excellent performance metrics, as verified by PageSpeed Insights:
| Metric | Desktop | Mobile | Target | 
|---|---|---|---|
| Performance | 99/100 | 92/100 | 90+ | 
| Accessibility | 100/100 | 100/100 | 100 | 
| Best Practices | 93/100 | 93/100 | 90+ | 
| SEO | 100/100 | 100/100 | 100 | 
These scores were achieved through several optimizations:
Build Configuration
The build pipeline is optimized through:
- Partial hydration with Astro
- Efficient code splitting
- Minimal client-side JavaScript
- Optimized asset handling
- Cloudflare Pages integration
CSS Optimization
The CSS architecture focuses on performance:
- Tailwind JIT compilation
- Custom utility classes
- Minimal base styles
- Dark mode optimization
- Typography-first approach
Deployment Pipeline
The site is deployed using Cloudflare Pages:
{
  "scripts": {
    "pages:dev": "pnpm run build && wrangler pages dev ./dist",
    "pages:deploy": "pnpm run build && wrangler pages deploy ./dist"
  }
}
Development Workflow
The development workflow is streamlined with key commands:
Local Development
pnpm dev              # Start development server
pnpm pages:dev        # Start with Cloudflare Pages
pnpm build           # Build for production
pnpm preview         # Preview production build
Code Quality
pnpm lint            # Run all linting
pnpm format          # Format all code
pnpm lint:types      # Type check
Deployment
pnpm pages:deploy    # Deploy to Cloudflare Pages
Lessons Learned
- 
Type Safety Investment: Proper TypeScript configuration prevented numerous potential issues and improved maintainability. 
- 
Automated Quality Checks: Pre-commit hooks with lint-staged maintain code quality without impeding development speed. 
- 
Performance by Design: The brutalist approach naturally led to excellent performance scores. 
- 
Developer Experience: Taking time to set up proper tooling and automation made the development process more enjoyable. 
- 
Build Pipeline: A well-configured build pipeline with proper type checking and linting catches issues early. 
Future Improvements
- Analytics: Adding privacy-focused analytics with proper TypeScript types
- API Integration: Adding a typed API layer for the contact form
- Testing: Adding Jest and Testing Library integration
- Performance Monitoring: Implementing automated performance tracking
- Component Library: Extracting reusable components into a shared library
Conclusion
Building montreuil.dev has been an exercise in balancing minimalist design with robust development practices. The result is not just a portfolio site, but a platform that’s enjoyable to maintain and extend.
The source code is available on GitHub - feel free to use it as inspiration for your own projects!