One of the biggest challenges with static site generators like Jekyll is implementing search functionality. Traditional server-side search requires databases and backend infrastructure, which GitHub Pages doesn’t support. But what if I told you we could build lightning-fast search that works entirely in the browser?

This article documents how we implemented a comprehensive search system for our Jekyll blog using Lunr.js - complete with fuzzy search, result highlighting, and mobile-responsive design.

The Challenge: Search on Static Sites

Why Search Matters

  • User Experience: Visitors expect to find content quickly
  • Content Discovery: Help readers find related articles
  • Site Usability: Reduce bounce rate from frustrated users
  • Professional Feel: Modern websites have search functionality

GitHub Pages Limitations

  • No Server-Side Code: Can’t run PHP, Python, or Node.js
  • No Database: Can’t use MySQL, PostgreSQL, or MongoDB
  • Static Files Only: HTML, CSS, JavaScript, and assets
  • No Custom Jekyll Plugins: Limited to whitelisted plugins

The Solution: Client-Side Search with Lunr.js

Instead of server-side search, we’ll build a JavaScript-powered search that:

  • Indexes content at build time
  • Searches instantly without server requests
  • Highlights matches for better user experience
  • Works offline once the page loads

Architecture Overview

flowchart TD A[Jekyll Build] --> B[Generate search.json] B --> C[Deploy to GitHub Pages] C --> D[User Visits Site] D --> E[Lunr.js Loads Index] E --> F[User Types Search] F --> G[Instant Results] G --> H[Highlighted Matches]

Implementation: Step-by-Step Guide

Step 1: Create the Search Data File

First, we need Jekyll to generate a JSON file containing all our content. Create search.json in your site root:

---
layout: null
---
[
  
    {
      "title": "Welcome to My New Jekyll Blog",
      "excerpt": "Introducing my new Jekyll-powered blog hosted on GitHub Pages, featuring separate sections for blog posts, technical articles, how-to guides, and project showcases.",
      "content": "I’m excited to launch my new blog built with Jekyll and hosted on GitHub Pages! This site serves as a central hub for sharing my thoughts, technical knowledge, and projects.What You’ll Find Here📝 Blog PostsRegular posts about my experiences in tech, industry insights, and personal reflections on development trends.📚 Technical ArticlesIn-depth guides and technical deep-dives covering various technologies, frameworks, and development practices.🔧 How-to GuidesStep-by-step tutorials to help others solve specific problems or set up development environments.💻 ProjectsA showcase of my development work, open source contributions, and side projects.Built With Modern ToolsThis site is built using:  Jekyll - Static site generator  GitHub Pages - Free hosting and automatic deployment  Liquid - Templating language for dynamic content  Markdown - Simple content authoring  CSS Grid & Flexbox - Modern responsive layoutsStay ConnectedFeel free to explore the different sections and don’t hesitate to reach out if you have questions or suggestions. You can find me on GitHub or through the contact methods listed in the footer.Happy coding! 🚀",
      "url": "/blog/announcement/2025/07/20/sample-post/",
      "date": "2025-07-20",
      "category": "",
      "tags": ["jekyll","github-pages","blogging","web-development"]
    },
  
    {
      "title": "GitHub as a CMS: My Real-World Experience",
      "excerpt": "Can GitHub really replace a traditional CMS? After 6 months of using GitHub + Jekyll for content management, here's what I learned about the good, the bad, and the surprising.",
      "content": "GitHub as a CMS: My Real-World ExperienceCan GitHub really replace a traditional CMS? After 6 months of using GitHub + Jekyll for all my content management, I have some thoughts (and battle scars) to share.The Unconventional ChoiceLet me start with why I even considered this. After dealing with WordPress for years - the constant updates, security patches, database issues, and $200/month hosting bills - I was ready for something different.When I saw how elegantly projects like React and Vue handle their documentation using static sites, I wondered: Could this work for regular blogging and content management too?Spoiler alert: It absolutely can, but there are some things I wish I’d known starting out.Why GitHub for Content Management?The Traditional Pain PointsBefore diving into the solution, let’s acknowledge what drove this decision:  CMS Complexity: WordPress, Drupal, and similar platforms require constant updates, security patches, and database maintenance  Vendor Lock-in: Proprietary platforms make content migration difficult  Performance Issues: Dynamic sites with databases introduce latency and complexity  Version Control: Most CMSs lack robust version control for content  Collaboration Friction: Traditional editing workflows don’t support modern development practicesThe GitHub AdvantageGitHub offers several compelling advantages as a content platform:graph TB    subgraph "Traditional CMS"        DB[Database]        SERVER[Web Server]        ADMIN[Admin Panel]        USERS[User Management]        PLUGINS[Plugin System]    end        subgraph "GitHub-Based System"        REPO[Git Repository]        MARKDOWN[Markdown Files]        ACTIONS[GitHub Actions]        PAGES[GitHub Pages]        JEKYLL[Jekyll Engine]    end        subgraph "Benefits"        VERSION[Version Control]        BACKUP[Automatic Backup]        COLLAB[Easy Collaboration]        FREE[Free Hosting]        FAST[Fast Performance]    end        REPO --> VERSION    MARKDOWN --> BACKUP    ACTIONS --> COLLAB    PAGES --> FREE    JEKYLL --> FASTThe Implementation JourneyPhase 1: The FoundationStarting with Jekyll seemed straightforward—until reality hit. Here’s what the initial setup looked like:Project Structure├── _articles/           # Technical articles collection├── _howtos/             # How-to guides collection  ├── _posts/              # Blog posts collection├── _layouts/            # Jekyll layout templates├── assets/css/          # Custom styling├── _config.yml          # Jekyll configuration├── index.html           # Homepage template├── about.md             # About page├── articles.md          # Articles listing page├── blog.md              # Blog listing page└── howtos.md            # How-tos listing pageThe First Reality CheckWhat I Expected: Smooth Jekyll setup with automatic content discoveryWhat Actually Happened: 8 hours of debugging why index.html was generating empty filesThis led to the first major lesson: Jekyll has quirks that aren’t immediately obvious.Phase 2: The Great Index.html MysteryThe most frustrating challenge came when the homepage stopped generating content. Despite successful builds, the generated _site/index.html was completely empty.The Debugging Process  Syntax Validation: Checked Liquid template syntax ✅  Layout Issues: Verified default.html layout ✅  Configuration Problems: Reviewed _config.yml ✅  Content Structure: Validated front matter ✅  Jekyll Logs: Build completed successfully ✅Everything looked perfect, but the output was empty.The SolutionThe breakthrough came when we discovered that Jekyll has specific issues processing root index.html files with complex Liquid templates. The workaround was initially renaming index.html to home.html, which worked perfectly.However, we eventually solved the root cause: missing collection index files. Jekyll’s content discovery depends on properly structured collection index files in directories like _articles/index.html and _howtos/index.html.Phase 3: Content ArchitectureThe key insight was organizing content into Jekyll collections rather than relying solely on posts:Collection Strategy# _config.ymlcollections:  articles:    output: true    permalink: /:collection/:name/  howtos:    output: true    permalink: /:collection/:name/This created three distinct content types:  Blog Posts (_posts/): Time-sensitive, personal thoughts  Technical Articles (_articles/): Comprehensive, evergreen technical content  How-to Guides (_howtos/): Step-by-step procedural contentContent Discovery Flowflowchart TD    A[New .md File Added] --> B{File Location?}        B -->|_posts/| C[Blog Posts Collection]    B -->|_articles/| D[Articles Collection]    B -->|_howtos/| E[How-tos Collection]        C --> F[Update Blog Index]    D --> G[Update Articles Index]    E --> H[Update How-tos Index]        F --> I[Regenerate Homepage]    G --> I    H --> I        I --> J[Content Live]What to Watch For: Common Pitfalls1. Jekyll Build MysteriesSymptom: Builds succeed but generate empty or incorrect filesCauses:  Missing layout files  Incorrect front matter  Broken Liquid syntax  Missing collection index filesSolution: Always check both build logs AND generated output files2. GitHub Pages vs Local DevelopmentThe Issue: Different Jekyll versions and plugin restrictions            Environment      Jekyll Version      Plugin Support                  Local Dev      4.3.0      All plugins              GitHub Pages      3.9.x      Whitelisted only      Best Practice: Use the github-pages gem to match production environment:# Gemfilegem "github-pages", group: :jekyll_plugins3. Content Organization ComplexityInitial Approach: Dump everything in _posts/Problem: No content categorization or different URL structuresSolution: Use collections for different content types4. Navigation GenerationChallenge: Maintaining consistent navigation across all pagesSolution: Centralize navigation in _layouts/default.html:<nav>  <a href="/">Home</a>  <a href="/blog/">Blog</a>  <a href="/articles/">Articles</a>  <a href="/howtos/">How-tos</a>  <a href="/about/">About</a></nav>The Workflow: From Idea to PublishedContent Creation ProcesssequenceDiagram    participant Writer as Content Creator    participant Editor as Text Editor    participant Git as Local Git    participant GitHub as GitHub    participant Pages as GitHub Pages    participant Site as Live Site        Writer->>Editor: Write content in Markdown    Editor->>Git: Save as .md file with front matter    Writer->>Git: git add .    Writer->>Git: git commit -m "New article"    Writer->>GitHub: git push origin main    GitHub->>Pages: Trigger automatic build    Pages->>Site: Deploy updated site    Site-->>Writer: Content live in 5-10 minutesReal-World ExampleCreating this very article involved:# 1. Create the filetouch _articles/github-document-management-blogging.md# 2. Add front matter and contentcat > _articles/github-document-management-blogging.md << 'EOF'---layout: posttitle: "GitHub as a Document Management and Blogging Platform"date: 2025-07-20category: "Technical"tags: [github, jekyll, blogging]---# Content here...EOF# 3. Commit and pushgit add .git commit -m "Add article on GitHub as blogging platform"git push origin mainPerformance and SEO BenefitsStatic Site AdvantagesThe GitHub + Jekyll combination delivers impressive performance:  Page Load Times: < 1 second (static files + CDN)  Zero Database Queries: No backend processing  Automatic CDN: GitHub Pages includes global CDN  HTTPS by Default: Built-in SSL certificatesSEO OptimizationJekyll automatically generates:  XML sitemaps  RSS feeds  Semantic HTML structure  Meta tags (with jekyll-seo-tag plugin)Cost Analysis: Free vs. Traditional Hosting            Aspect      GitHub Pages      Traditional Hosting                  Hosting Cost      $0/month      $5-50/month              Domain      Custom domain supported      Included/Extra              SSL Certificate      Free      $0-100/year              CDN      Included      $10-50/month              Backup      Git history      Extra service              Collaboration      Built-in      Extra tools needed      Advanced Features: Beyond Basic Blogging1. Documentation as CodeUsing the same repository for both blog and technical documentation:docs/├── api/│   ├── authentication.md│   └── endpoints.md├── guides/│   ├── getting-started.md│   └── advanced-usage.md└── index.md2. Collaborative EditingGitHub’s collaboration features work perfectly for content:  Pull Requests: Review content before publishing  Issues: Track content ideas and improvements  Projects: Plan content calendars  Actions: Automate content workflows3. Multi-Site ManagementOne repository can power multiple sites:  Main blog at custom domain  Documentation site at /docs  Project pages for different initiativesLessons Learned: Best Practices1. Start Simple, Evolve GraduallyDon’t: Try to build a complex multi-collection system immediatelyDo: Start with basic posts, add collections as needs grow2. Invest in Good DocumentationWhy: Future you will thank present youHow: Document your Jekyll setup, custom configurations, and workflows3. Use Meaningful Commit Messages# Badgit commit -m "Update"# Good  git commit -m "Add technical article on microservices patterns- Cover service discovery approaches- Include code examples for Node.js and Python- Add performance comparison section"4. Leverage GitHub Features  Templates: Create issue templates for content ideas  Actions: Automate link checking, spell checking  Projects: Plan content calendars  Discussions: Engage with readersWhen GitHub Blogging Makes SensePerfect Fit Scenarios  Technical Blogs: Developer-focused content with code examples  Documentation Sites: Project documentation that evolves with code  Personal Brands: Developers, writers, consultants wanting full control  Team Blogs: Organizations with technical teams comfortable with GitWhen to Consider Alternatives  Non-Technical Teams: Learning curve may be too steep  Complex User Management: Multiple author permissions and roles  Advanced CMS Features: Comments, user registration, e-commerce  Real-Time Content: News sites requiring immediate publishingThe Verdict: Surprisingly PowerfulAfter this deep dive into GitHub-based content management, the results are compelling:Pros✅ Zero hosting costs with professional features✅ Excellent performance through static site generation✅ Version control for all content changes✅ Collaborative workflows using familiar developer tools✅ Future-proof content in portable Markdown format✅ Professional documentation capabilitiesCons❌ Learning curve for non-technical users❌ Limited dynamic features (comments, user accounts)❌ GitHub dependency (though content is portable)❌ Jekyll quirks require debugging skillsGetting Started: Your First Steps1. Repository Setup# Create new repositorygh repo create your-blog --public# Clone locallygit clone https://github.com/yourusername/your-blog.gitcd your-blog# Initialize Jekylljekyll new . --force2. Essential Configuration# _config.ymltitle: "Your Blog Name"description: "Your blog description"url: "https://yourusername.github.io"baseurl: ""# Collections (optional)collections:  articles:    output: true    permalink: /:collection/:name/# Pluginsplugins:  - jekyll-feed  - jekyll-seo-tag  - jekyll-sitemap3. Enable GitHub Pages  Go to repository Settings  Navigate to Pages section  Select source: “Deploy from a branch”  Choose branch: main or gh-pages  Wait 5-10 minutes for first deploymentConclusion: A Paradigm ShiftUsing GitHub as a blogging and document management platform represents a fundamental shift from traditional content management. While it requires some technical comfort, the benefits—cost savings, performance, version control, and collaboration—make it compelling for many use cases.The key insight from this journey: the best content management system is one that gets out of your way and lets you focus on creating great content. For developers and technical teams, GitHub provides exactly that.Whether you’re building a personal blog, team documentation, or company technical content, this approach deserves serious consideration. The initial learning curve pays dividends in long-term maintainability, performance, and cost savings.Ready to try it yourself? Start with a simple Jekyll blog, add content gradually, and evolve the system as your needs grow. The GitHub + Jekyll combination might just revolutionize how you think about content management.Have you tried GitHub for content management? What challenges did you face? Share your experiences in the comments or reach out on GitHub to continue the conversation.",
      "url": "/blogging/technology/2025/07/19/github-as-cms-experience/",
      "date": "2025-07-19",
      "category": "",
      "tags": ["github","cms","jekyll","static-sites","experience-report"]
    },
  
    {
      "title": "My Journey to GitHub-Powered Blogging",
      "excerpt": "Why I ditched traditional CMSs for GitHub + Jekyll and never looked back. A personal journey through the challenges and victories of static site blogging.",
      "content": "My Journey to GitHub-Powered BloggingAfter years of wrestling with WordPress updates, database crashes, and hosting bills, I finally made the leap to something radically different: GitHub as my blogging platform. Here’s my honest take on why this approach changed everything.The Breaking PointLet me paint you a picture: It’s 2 AM, my WordPress site is down (again), and I’m frantically trying to restore from backups while my hosting provider’s support chat shows “average wait time: 47 minutes.” Sound familiar?That night, I decided enough was enough. There had to be a better way.The GitHub + Jekyll DiscoveryThe solution came from an unexpected place - watching how software documentation was evolving. Projects like React, Vue, and countless others were using static site generators with remarkable success.The lightbulb moment: If it’s good enough for Facebook’s React docs, it’s good enough for my blog.What I DiscoveredThe Good✅ $0/month hosting with GitHub Pages✅ Version control for content - never lose a post again✅ Lightning-fast performance - sub-1-second page loads✅ No more database headaches - everything is just files✅ Built-in backup - everything lives in Git✅ Markdown writing - focus on content, not formattingThe Challenges❌ Learning curve - Git workflows aren’t for everyone❌ No real-time editing - need to rebuild for changes❌ Comment systems require third-party solutions❌ Initial setup can be intimidatingThe 8-Hour Debug StorySpeaking of challenges, let me share the debugging marathon that nearly broke me. After setting up my beautiful Jekyll site, everything looked perfect locally. But when I pushed to GitHub Pages… blank page. Nothing. Nada.Eight hours later (yes, eight), I discovered the culprit: an empty index.html file that was overriding my carefully crafted homepage. One file deletion, and suddenly my site came to life.Lesson learned: Sometimes the simplest things cause the biggest headaches.Why I’m Never Going BackSix months in, and I’m completely sold. Writing in Markdown feels natural, version control gives me peace of mind, and the performance is incredible. Most importantly, I spend time writing content instead of maintaining infrastructure.For Fellow DevelopersIf you’re a developer tired of CMS maintenance, this approach might revolutionize your workflow. The combination of familiar Git workflows, Markdown simplicity, and zero hosting costs creates a compelling package.The Bottom LineGitHub + Jekyll isn’t for everyone, but for those willing to embrace a developer-centric approach to blogging, it’s transformative. The initial investment in learning pays dividends in reduced maintenance, better performance, and a more enjoyable writing experience.Want to see how this site is built? Check out the complete setup on GitHub - it’s all open source!  Uses relevant hashtags for discoverability  Links directly to your repositoryPerfect for LinkedIn, Twitter, or Dev.to! 🎯",
      "url": "/blogging/journey/2025/07/18/github-blogging-journey/",
      "date": "2025-07-18",
      "category": "",
      "tags": ["github","jekyll","cms","blogging","personal-experience"]
    },
  
    {
      "title": "Understanding Jekyll Collections: When Posts Aren't Enough",
      "excerpt": "Jekyll posts work great for chronological content, but what about organizing tutorials, documentation, or project showcases? Here's when and how to use Jekyll collections effectively.",
      "content": "If you’ve been using Jekyll for a while, you’ve probably run into this problem: not everything fits neatly into the chronological blog post model.That’s where Jekyll collections come in - and honestly, they’re a game-changer once you understand how to use them properly.What Are Jekyll Posts?Posts are Jekyll’s original content type, designed for chronological content like blog entries.Characteristics of Posts  Date-based: Filenames must include dates (YYYY-MM-DD-title.md)  Chronological ordering: Automatically sorted by date  Built-in pagination: Easy to paginate through posts  RSS feeds: Automatically included in site feeds  Categories and tags: Built-in taxonomy supportExample Post Structure---layout: posttitle: "My Blog Post"date: 2025-07-20categories: [blogging, jekyll]tags: [tutorial, web-development]---What Are Jekyll Collections?Collections are groups of related documents that don’t need to follow chronological order.Characteristics of Collections  Flexible naming: No date requirements in filenames  Custom organization: Organize by topic, not time  Custom metadata: Define your own front matter fields  Flexible URLs: Control permalink structure  Queryable: Easy to filter and sort programmaticallyExample Collection Structure---layout: posttitle: "API Documentation"category: "technical"difficulty: "advanced"version: "2.1"last_updated: 2025-07-20---When to Use EachUse Posts For:  Blog entries - Personal thoughts, announcements, news  Time-sensitive content - Updates, releases, events  Chronological narratives - Project progress, learning journeys  Regular publishing - Weekly updates, monthly reviewsUse Collections For:  Documentation - API docs, user guides, tutorials  Portfolio items - Projects, case studies, work samples  Reference material - Recipes, tools, resources  Structured content - Team members, products, servicesSetting Up Collections1. Configure in _config.ymlcollections:  tutorials:    output: true    permalink: /tutorials/:name/  projects:    output: true    permalink: /work/:name/2. Create Collection Directories_tutorials/  getting-started.md  advanced-techniques.md_projects/  project-alpha.md  project-beta.md3. Set Default Layoutsdefaults:  - scope:      path: "_tutorials"      type: "tutorials"    values:      layout: "tutorial"      category: "learning"Practical ExamplesBlog Post Example---layout: posttitle: "Why I Switched to Jekyll"date: 2025-07-20categories: [blogging, tools]tags: [jekyll, static-sites, productivity]---Last month, I decided to migrate my blog from WordPress to Jekyll...Collection Item Example---layout: projecttitle: "E-commerce Platform"technology: ["React", "Node.js", "MongoDB"]status: "completed"client: "TechCorp"duration: "6 months"featured: true---This project involved building a scalable e-commerce platform...Advanced TechniquesQuerying CollectionsCross-referencing Content<!-- In a blog post, reference related how-tos -->Custom SortingBest PracticesContent Organization  Use descriptive filenames: advanced-git-workflows.md not tutorial1.md  Consistent front matter: Define standard fields for each collection  Logical grouping: Group related content in the same collectionPerformance Considerations  Limit collection size: Large collections can slow build times  Use pagination: For collections with many items  Optimize images: Compress images in collection itemsSEO Optimization  Unique titles: Each item should have a distinct title  Meta descriptions: Use excerpts or custom descriptions  Structured data: Add schema markup for better search visibilityConclusionChoose posts for time-based content and collections for everything else. This approach gives you the flexibility to organize content logically while maintaining Jekyll’s simplicity and power.The key is understanding your content’s nature and choosing the right tool for the job. Most sites benefit from using both: posts for regular updates and collections for structured, reference material.",
      "url": "/web-development/jekyll/2025/07/17/understanding-jekyll-collections/",
      "date": "2025-07-17",
      "category": "",
      "tags": ["jekyll","collections","static-sites","organization","blogging"]
    },
  
    {
      "title": "The Hidden Cost of Technical Debt: A Developer's Confession",
      "excerpt": "Technical debt isn't just a buzzword - it's a silent productivity killer. Here's what I learned after inheriting a codebase with 3 years of accumulated shortcuts.",
      "content": "The Hidden Cost of Technical Debt: A Developer’s ConfessionLast month, I inherited a codebase that looked deceptively simple from the outside. Clean UI, working features, happy users. But underneath? Three years of accumulated shortcuts, quick fixes, and “we’ll refactor this later” promises.What I discovered changed how I think about code quality forever.The Innocent BeginningThe project started innocently enough. A startup MVP built under tight deadlines with the classic “ship first, optimize later” mentality. The team delivered on time, users were happy, and investors were pleased.But then came the feature requests. And bug fixes. And “just one more quick integration.”Each addition came with the same refrain: “Let’s just get this working, we’ll clean it up in the next sprint.”The Reality CheckThree years later, I stepped into this codebase, and here’s what I found:The Numbers Don’t Lie  47 TODO comments scattered throughout the code  23 “temporary” workarounds that became permanent  11 different ways to handle the same API call  Average bug fix time: 3.2 days (should have been hours)  New feature velocity: 40% slower than team estimatesThe Daily Frustrations  Simple changes rippled through 8+ files  Testing required mental gymnastics to understand dependencies  New team members took 3x longer to onboard  Bug fixes often introduced new bugsThe Breaking PointThe moment I realized the true cost came during what should have been a “simple” feature addition. Adding user profile pictures - a 2-hour task in a clean codebase - took two weeks.Why? Because the user authentication system was tightly coupled to the notification system, which was hardcoded to the email service, which had three different implementations across the app.That’s when I understood: technical debt isn’t just about code - it’s about human productivity.The Real Cost of ShortcutsHere’s what technical debt actually costs:Developer MoraleNothing kills enthusiasm faster than dreading every code change. I watched talented developers become frustrated, not because they couldn’t solve problems, but because the codebase fought them at every turn.Feature VelocityWhat should take days takes weeks. Innovation slows to a crawl because you’re constantly working around existing problems instead of building forward.Bug MultiplicationIn a tightly coupled system, every fix is a potential source of new bugs. We spent more time testing edge cases than implementing features.Knowledge HoardingWhen code is complex and poorly documented, knowledge becomes siloed. Only certain developers can touch certain parts of the system, creating dangerous dependencies.The Turnaround StrategyAfter documenting the pain points, I presented a case for addressing technical debt that resonated with leadership: frame it as a productivity investment, not just code cleanup.Week 1-2: Documentation Sprint  Mapped all critical dependencies  Documented the “why” behind confusing code  Created onboarding guides for new developersWeek 3-6: Decoupling Phase  Identified the top 5 tightly coupled systems  Created clear interfaces between components  Established coding standards and review processesWeek 7-8: Testing Infrastructure  Added comprehensive test coverage  Implemented automated testing pipelines  Created deployment safety netsThe ResultsSix weeks later, the transformation was remarkable:  Bug fix time: Down to 4 hours average  Feature velocity: 150% improvement  Developer satisfaction: Night and day difference  New hire onboarding: Reduced from 3 weeks to 1 weekLessons for Other Developers1. Technical Debt Is a Business DecisionDon’t frame refactoring as “making the code prettier.” Frame it as “increasing team productivity by 40%” or “reducing bug fix time by 80%.”2. Start Small, Measure ImpactDon’t try to refactor everything at once. Pick one painful area, fix it, measure the improvement, then use those results to justify larger efforts.3. Documentation Is Debt PreventionEvery undocumented decision is future technical debt. If you’re taking a shortcut, at least document why and what the “proper” solution would be.4. Code Reviews Are Your Safety NetThe best time to catch technical debt is before it enters the codebase. Invest in thorough code reviews and clear standards.The Ongoing BattleTechnical debt isn’t a one-time problem - it’s an ongoing challenge that requires constant vigilance. But here’s what I learned: a little prevention is worth massive amounts of cure.Now, when I’m tempted to take a shortcut, I ask myself: “How will this feel to debug at 2 AM six months from now?”Usually, that’s enough motivation to do it right the first time.Have your own technical debt horror stories? I’d love to hear them. Sometimes sharing these experiences helps us all write better code.",
      "url": "/development/insights/2025/07/16/technical-debt-confession/",
      "date": "2025-07-16",
      "category": "",
      "tags": ["technical-debt","software-development","code-quality","lessons-learned"]
    },
  
    {
      "title": "AI Tools Are Changing How I Code (But Not How You Think)",
      "excerpt": "After 6 months with AI coding assistants, here's what actually changed about my development process - and what surprisingly stayed the same.",
      "content": "The AI coding revolution is here, and it’s… not quite what I expected.Six months ago, I started using GitHub Copilot and other AI coding assistants. Everyone was talking about AI “replacing developers” or “10x productivity gains.” After living with these tools daily, I have a more nuanced take.AI tools absolutely changed how I code, just not in the ways the hype suggested.What Changed: The Unexpected Benefits1. Faster Boilerplate, More Creative EnergyThe biggest win isn’t AI writing complex algorithms for me - it’s handling the tedious stuff. Setting up Express routes, writing test fixtures, creating TypeScript interfaces… all the mechanical typing that drains mental energy.Result: I spend more time thinking about architecture and user experience, less time fighting syntax.2. Better Documentation HabitsHere’s something unexpected: AI tools made me a better documenter. When Copilot suggests code based on my comments, I started writing more detailed comments to get better suggestions.Example:// Before: function to get user data// After: fetch user profile including avatar, preferences, and recent activity from the REST APIThe more descriptive I am, the better the AI suggestions. Win-win.3. Exploration Without FearAI tools lowered the barrier to trying new libraries or patterns. Instead of spending hours reading documentation, I can describe what I want and get a working example to start from.This led me to discover several libraries I wouldn’t have tried otherwise.What Didn’t Change: The Reality Check1. Debugging Is Still All MeAI can generate code, but debugging complex issues? That’s still entirely human work. Understanding why something breaks requires context, domain knowledge, and intuition that AI doesn’t have.The ratio: AI helps with maybe 20% of my debugging time (writing test cases), but the other 80% is pure detective work.2. Architecture Decisions Matter More Than EverWith AI generating code faster, the quality of your architecture becomes even more critical. It’s easier to build the wrong thing quickly now.I spend more time upfront thinking about:  Data flow and state management  Component boundaries and responsibilities  Testing strategies and error handling3. Code Review Is More ImportantAI-generated code isn’t always optimal. It works, but it might not follow your team’s patterns, handle edge cases, or consider performance implications.New habit: I review AI suggestions as carefully as I’d review a junior developer’s code.The Subtle Productivity GainsThe real productivity improvement isn’t dramatic - it’s cumulative. Lots of small time savings throughout the day:  5 minutes saved writing a regex pattern  10 minutes saved setting up a new React component  15 minutes saved writing repetitive test cases  20 minutes saved converting data between formatsAdd it up over a week, and I’m saving 2-3 hours. Not revolutionary, but meaningful.What I Learned About LearningIronically, AI tools made me more conscious about staying sharp on fundamentals. When a tool can generate code for you, understanding why that code works becomes more important, not less.New learning approach:  Let AI generate initial code  Understand every line before using it  Research the patterns and principles behind it  Practice implementing variations manuallyThe Collaboration AngleWorking with AI feels like pair programming with a very knowledgeable but literal-minded partner. Great at implementation details, needs guidance on the bigger picture.Best practices I developed:  Start with clear, detailed comments about intent  Break complex problems into smaller, well-defined pieces  Always validate AI suggestions against requirements  Use AI for exploration, human judgment for decisionsThe Tools That StuckAfter trying various AI coding assistants:GitHub Copilot: Best for day-to-day coding, great context awarenessChatGPT: Excellent for explaining complex concepts and debugging helpTabnine: Good for teams with specific coding patternsThe surprise winner: Simple GPT conversations for rubber duck debugging. Explaining a problem to AI often helps me solve it myself.Looking ForwardAI coding tools aren’t replacing developers - they’re changing what we focus on. Less time on mechanical tasks, more time on creative problem-solving and user experience.The developers thriving are those who embrace AI as a productivity multiplier while staying sharp on fundamentals and system thinking.The ones struggling are either afraid to try new tools or expect AI to do all the thinking for them.My Honest RecommendationTry AI coding tools, but manage your expectations. They’re powerful assistants, not magic solutions. The fundamentals of good software development - clear thinking, solid architecture, thorough testing - matter more than ever.And remember: the best AI tool is still the one between your ears.What’s your experience with AI coding tools? I’m curious to hear how they’ve changed (or not changed) your development process.",
      "url": "/ai/development/productivity/2025/07/15/ai-coding-reality-check/",
      "date": "2025-07-15",
      "category": "",
      "tags": ["ai","coding","github-copilot","productivity","developer-tools"]
    }
  
  
]

Key Features:

  • Includes all collections (posts, articles, howtos)
  • Strips HTML from content for clean searching
  • Escapes quotes to prevent JSON syntax errors
  • Generates at build time so it’s always current

Step 2: Build the Search Interface

Add a search box to your layout (_layouts/default.html):

<div class="search-wrapper">
    <div id="search-container" class="search-container">
        <input type="text" id="search-input" placeholder="Search articles..." autocomplete="off">
        <div id="search-results" class="search-results"></div>
    </div>
</div>

Design Considerations:

  • Autocomplete disabled to prevent browser interference
  • Container structure for absolute positioning
  • Semantic HTML for accessibility

Step 3: Implement Search Logic

Create assets/js/search.js with Lunr.js integration:

// Load search data and build index
function loadSearchData() {
    fetch('/search.json')
        .then(response => response.json())
        .then(data => {
            searchData = data;
            buildSearchIndex();
        });
}

function buildSearchIndex() {
    searchIndex = lunr(function() {
        this.field('title', { boost: 10 });      // Titles are most important
        this.field('excerpt', { boost: 7 });     // Excerpts are highly relevant
        this.field('content', { boost: 5 });     // Content is searchable
        this.field('tags', { boost: 3 });        // Tags help categorization
        this.field('category', { boost: 3 });    // Categories for filtering
        this.ref('id');

        searchData.forEach(function(doc, index) {
            doc.id = index;
            this.add(doc);
        }, this);
    });
}

Search Features:

  • Weighted Fields: Titles matter more than content
  • Fuzzy Matching: Handles typos and partial words
  • Multiple Fields: Searches across all content types
  • Performance Optimized: Builds index once, searches instantly

Step 4: Add Professional Styling

Style the search interface with responsive CSS:

.search-wrapper {
    position: relative;
    flex: 1;
    max-width: 400px;
    margin: 0 2rem;
}

#search-input {
    width: 100%;
    padding: 0.75rem 1rem;
    border: 2px solid var(--border);
    border-radius: var(--radius);
    transition: all 0.3s ease;
}

#search-input:focus {
    border-color: var(--accent);
    box-shadow: 0 0 0 3px rgba(52, 152, 219, 0.1);
}

.search-results {
    position: absolute;
    background: white;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: 0 8px 30px rgba(0,0,0,0.12);
    max-height: 400px;
    overflow-y: auto;
}

Visual Design:

  • Clean Interface: Minimal, professional appearance
  • Focus States: Clear visual feedback
  • Dropdown Results: Non-intrusive result display
  • Responsive: Works on all screen sizes

Advanced Features We Implemented

1. Smart Result Highlighting

function highlightText(text, query) {
    const words = query.split(/\s+/).filter(word => word.length > 1);
    let highlightedText = text;

    words.forEach(word => {
        const regex = new RegExp(`(${escapeRegex(word)})`, 'gi');
        highlightedText = highlightedText.replace(regex, '<mark>$1</mark>');
    });

    return highlightedText;
}

Highlighting Features:

  • Multi-word Support: Highlights each search term
  • Case Insensitive: Finds matches regardless of case
  • Safe HTML: Escapes special characters
  • Visual Emphasis: Uses <mark> tags for styling

2. Intelligent Snippet Generation

function createSnippet(content, query) {
    const words = query.toLowerCase().split(/\s+/);
    const sentences = content.split(/[.!?]+/);
    
    // Find sentence containing most query terms
    let bestSentence = '';
    let maxMatches = 0;
    
    sentences.forEach(sentence => {
        const lowerSentence = sentence.toLowerCase();
        const matches = words.filter(word => lowerSentence.includes(word)).length;
        
        if (matches > maxMatches) {
            maxMatches = matches;
            bestSentence = sentence.trim();
        }
    });

    return highlightText(bestSentence.substring(0, 200) + '...', query);
}

Smart Snippets:

  • Context Aware: Shows sentences containing search terms
  • Relevant Excerpts: Not just first 200 characters
  • Highlighted Terms: Shows why the result matched
  • Proper Length: Balances detail with readability

3. Mobile-Responsive Design

@media (max-width: 768px) {
    .search-wrapper {
        display: none; /* Hide from nav on mobile */
    }
    
    .mobile-search .search-wrapper {
        display: block;
        max-width: none;
        margin: 0;
    }
}

Mobile Strategy:

  • Dedicated Search Page: Better mobile experience
  • Full-Width Input: Easier typing on small screens
  • Touch-Friendly: Proper spacing and sizing
  • Navigation Link: Easy access from menu

Performance Optimization

Index Size Management

Content Type Index Weight Justification
Title 10x Most important for relevancy
Excerpt 7x Carefully crafted summaries
Content 5x Full text for comprehensive search
Tags 3x Categorical relevance
Category 3x Broad topic matching

Loading Strategy

// Lazy load search only when needed
document.addEventListener('DOMContentLoaded', function() {
    const searchInput = document.getElementById('search-input');
    if (searchInput) {
        loadSearchData(); // Only load if search exists
    }
});

Performance Benefits:

  • Conditional Loading: Only loads on pages with search
  • CDN Delivery: Lunr.js served from fast CDN
  • Compressed JSON: Minimal data transfer
  • Cached Results: Index built once per session

Real-World Results

Search Capabilities

Our implementation can find content by:

  • Exact Phrases: “github pages jekyll”
  • Partial Words: “merm” finds “mermaid” content
  • Multiple Terms: “diagram visualization” finds both
  • Categories: “technical” shows all technical articles
  • Tags: “javascript” finds JS-related content
  • Fuzzy Matching: “diagramming” finds “diagram” content

User Experience Features

sequenceDiagram participant User participant Search as Search Box participant Lunr as Lunr.js participant Results as Results Panel User->>Search: Types "mermaid" Search->>Lunr: Query index Lunr->>Results: Return matches Results->>User: Show highlighted results User->>Results: Click article link Results->>User: Navigate to content

Instant Results: No loading spinners or delays
Fuzzy Matching: Handles typos and variations
Context Snippets: Shows why results match
Category Filtering: Visual category indicators
Mobile Friendly: Responsive design for all devices
Keyboard Navigation: Accessible interface

Troubleshooting Common Issues

Issue 1: Search Index Not Loading

Symptoms: No results for any search terms Solutions:

  1. Check browser console for 404 errors on search.json
  2. Verify Jekyll is generating the JSON file correctly
  3. Ensure proper JSON syntax (no trailing commas)

Issue 2: Poor Search Results

Symptoms: Relevant content not appearing in results Solutions:

  1. Adjust field weights in Lunr configuration
  2. Check content is properly indexed (no HTML artifacts)
  3. Verify search terms exist in content

Issue 3: Mobile Display Problems

Symptoms: Search interface broken on mobile Solutions:

  1. Test responsive CSS breakpoints
  2. Check touch target sizes (minimum 44px)
  3. Verify mobile search page functionality

Alternative Approaches

Server-Side Solutions

  • Algolia: Hosted search service (paid)
  • Elasticsearch: Self-hosted search engine
  • Swiftype: Commercial search service

Static Site Solutions

  • Jekyll Plugins: Limited GitHub Pages support
  • Pre-built Indexes: Generated during CI/CD
  • External APIs: Third-party search services

Why Client-Side Works Best

  • GitHub Pages Compatible: No server requirements
  • Zero Cost: No hosting or service fees
  • Fast Performance: No network requests after load
  • Full Control: Complete customization possible

Implementation Checklist

Ready to add search to your Jekyll site?

  • Create search.json with Liquid templating
  • Add Lunr.js CDN to layout
  • Implement search JavaScript functionality
  • Style search interface with responsive CSS
  • Add search box to site navigation
  • Create dedicated mobile search page
  • Test with various search terms
  • Verify mobile responsiveness
  • Check performance on slow connections
  • Add search tips for users

Lessons Learned

What Worked Exceptionally Well

  • Client-side approach eliminates server complexity
  • Lunr.js provides excellent search capabilities
  • JSON generation keeps index automatically updated
  • Responsive design works across all devices

What We’d Improve Next Time

  • Search analytics to understand user behavior
  • Auto-suggestions for common search terms
  • Search filters by date, category, or tags
  • Keyboard shortcuts for power users

Conclusion: Search That Actually Works

Implementing client-side search in Jekyll proves that static sites can offer dynamic functionality without sacrificing simplicity. Our solution provides:

  • Professional search experience rivaling dynamic sites
  • Zero infrastructure costs perfect for GitHub Pages
  • Lightning-fast performance with instant results
  • Complete customization tailored to our content

The combination of Jekyll’s content generation, Lunr.js’s search capabilities, and thoughtful UX design creates a search experience that users love and developers can maintain.

Ready to implement search on your Jekyll site? Follow our step-by-step guide above, and your readers will thank you for making your content more discoverable.

Next Steps

Want to enhance your Jekyll site further? Check out these related articles:


Questions about implementing search functionality? Found an even better approach? Share your experience in the comments or reach out on GitHub to continue the conversation.