# How Mustache Templating Powers Resume Generation in GitHub Resume

> Discover how Mustache templating dynamically generates résumés by merging GitHub API JSON data with HTML templates client-side for fast, serverless resume creation.

- Repository: [GitHub resume generator/resume.github.com](https://github.com/resume/resume.github.com)
- Tags: how-to-guide
- Published: 2026-03-04

---

**Mustache templating generates dynamic résumés by merging static HTML templates with JSON data from the GitHub API, rendering the final page entirely on the client side without server-side processing.**

The resume.github.com project transforms GitHub profiles into polished résumés using client-side Mustache templating. Instead of server-side rendering, the application fetches static HTML templates and populates them with data retrieved from the GitHub API, creating a lightweight, dynamic user experience.

## The Mustache Templating Architecture

### Template Loading Strategy

Located in [`js/githubresume.js`](https://github.com/resume/resume.github.com/blob/main/js/githubresume.js) (lines 998-1003), the application determines which template to load based on the GitHub account type. For individual users, it fetches [`views/resume.html`](https://github.com/resume/resume.github.com/blob/main/views/resume.html); for organizations, it uses [`views/resumeOrgs.html`](https://github.com/resume/resume.github.com/blob/main/views/resumeOrgs.html).

```javascript
// githubresume.js – line 998-1003
var resume = (data.type == 'User' ? 'views/resume.html' :
              'views/resumeOrgs.html');
$.ajax({
    url: resume,
    dataType: 'html',
    success: function(data) {
        var template = data,
            html = Mustache.to_html(template, view);
        $('#resume').html(html);
});

```

### View Object Construction

Before rendering, the script constructs a `view` object (lines 22-39 in [`js/githubresume.js`](https://github.com/resume/resume.github.com/blob/main/js/githubresume.js)) that maps GitHub API fields to template variables. This object includes user metadata, repository counts, follower statistics, and derived fields like `userStatus` and `since`.

```javascript
// githubresume.js – lines 22-39
var view = {
    name: name,
    type: data.type,
    email: data.email,
    gravatar_id: data.gravatar_id,
    avatar_url: avatar,
    repos: data.public_repos,
    reposLabel: data.public_repos > 1 ? 'repositories' : 'repository',
    followers: data.followers,
    followersLabel: data.followers > 1 ? 'followers' : 'follower',
    username: username,
    userStatus: getUserStatus(),
    since: since,
    resume_url: window.location
};

```

## Rendering Process

### Main Resume Template

The `Mustache.to_html()` function merges the template with the view object. In [`views/resume.html`](https://github.com/resume/resume.github.com/blob/main/views/resume.html), placeholders like `{{name}}`, `{{userStatus}}`, and conditional blocks like `{{#gravatar_id}}` render user-specific content.

```html
<!-- views/resume.html -->
<h1 class="fn">{{name}}</h1>
<h2>{{userStatus}}</h2>
{{#gravatar_id}}
<img src="https://secure.gravatar.com/avatar/{{gravatar_id}}?s=140&d=…" class="photo"/>
{{/gravatar_id}}
{{#email}}<a href="mailto:{{email}}" class="email">{{email}}</a>{{/email}}

```

### Fragment Templates for Dynamic Content

After the main template renders, the application loads secondary templates for specific sections. Files like [`views/job.html`](https://github.com/resume/resume.github.com/blob/main/views/job.html), [`views/contrib.html`](https://github.com/resume/resume.github.com/blob/main/views/contrib.html), and [`views/org.html`](https://github.com/resume/resume.github.com/blob/main/views/org.html) receive their own view objects containing repository details, contribution statistics, and organization memberships.

Each fragment template is processed using the same `Mustache.to_html(template, view)` pattern, allowing modular rendering of repository lists, contribution graphs, and organizational affiliations without reloading the page.

## Key Source Files and Implementation Details

| File | Role | Link |
|------|------|------|
| [`js/githubresume.js`](https://github.com/resume/resume.github.com/blob/main/js/githubresume.js) | Core JavaScript: fetches GitHub data, builds the `view` objects, loads Mustache templates and renders them. | [githubresume.js](https://github.com/resume/resume.github.com/blob/master/js/githubresume.js) |
| [`views/resume.html`](https://github.com/resume/resume.github.com/blob/main/views/resume.html) | Main Mustache template for a regular user résumé. | [resume.html](https://github.com/resume/resume.github.com/blob/master/views/resume.html) |
| [`views/resumeOrgs.html`](https://github.com/resume/resume.github.com/blob/main/views/resumeOrgs.html) | Template used when the target is a GitHub organization. | [resumeOrgs.html](https://github.com/resume/resume.github.com/blob/master/views/resumeOrgs.html) |
| [`views/job.html`](https://github.com/resume/resume.github.com/blob/main/views/job.html) | Fragment template that renders each repository entry (language bar, description, stars, forks). | [job.html](https://github.com/resume/resume.github.com/blob/master/views/job.html) |
| [`views/contrib.html`](https://github.com/resume/resume.github.com/blob/main/views/contrib.html) | Fragment template for the contributions list (merged PRs). | [contrib.html](https://github.com/resume/resume.github.com/blob/master/views/contrib.html) |
| [`views/org.html`](https://github.com/resume/resume.github.com/blob/main/views/org.html) | Fragment template for the organizations section. | [org.html](https://github.com/resume/resume.github.com/blob/master/views/org.html) |
| [`index.html`](https://github.com/resume/resume.github.com/blob/main/index.html) | Entry point; loads Mustache library ([`mustache.js`](https://github.com/resume/resume.github.com/blob/main/mustache.js)) and starts the JavaScript app. | [index.html](https://github.com/resume/resume.github.com/blob/master/index.html) |

These files together illustrate the full flow: **data → view object → Mustache template → rendered résumé**.

## Summary

- Mustache templating enables fully client-side résumé generation without server-side rendering
- The `view` object in [`js/githubresume.js`](https://github.com/resume/resume.github.com/blob/main/js/githubresume.js) bridges GitHub API data and HTML templates
- Template selection logic distinguishes between individual users ([`views/resume.html`](https://github.com/resume/resume.github.com/blob/main/views/resume.html)) and organizations ([`views/resumeOrgs.html`](https://github.com/resume/resume.github.com/blob/main/views/resumeOrgs.html))
- Fragment templates ([`views/job.html`](https://github.com/resume/resume.github.com/blob/main/views/job.html), [`views/contrib.html`](https://github.com/resume/resume.github.com/blob/main/views/contrib.html)) handle dynamic content sections
- The `Mustache.to_html()` function performs the final template-to-HTML transformation

## Frequently Asked Questions

### What is Mustache templating and why is it used in resume.github.com?

Mustache is a logic-less template syntax that uses double braces for variable substitution. The resume.github.com project uses it to separate presentation (HTML templates) from data (GitHub API responses), enabling clean client-side rendering without server-side dependencies. This approach keeps the application lightweight and allows the same JavaScript code to serve different layouts for users versus organizations.

### How does the application decide which template to load?

The JavaScript code in [`js/githubresume.js`](https://github.com/resume/resume.github.com/blob/main/js/githubresume.js) checks the `data.type` property from the GitHub API response. If the value is "User", it loads [`views/resume.html`](https://github.com/resume/resume.github.com/blob/main/views/resume.html); otherwise, it loads [`views/resumeOrgs.html`](https://github.com/resume/resume.github.com/blob/main/views/resumeOrgs.html) for organizations. This conditional logic ensures that individuals see repository-focused layouts while organizations display member and team information.

### Can I customize the Mustache templates for my own résumé?

Yes, the template files in the `views/` directory are standard Mustache HTML files. You can modify [`resume.html`](https://github.com/resume/resume.github.com/blob/main/resume.html), [`job.html`](https://github.com/resume/resume.github.com/blob/main/job.html), or other fragments to change the layout, styling, or content structure, provided you maintain the variable names expected by the `view` object in [`githubresume.js`](https://github.com/resume/resume.github.com/blob/main/githubresume.js). Since rendering happens client-side, any changes to these templates take effect immediately without rebuilding the application.

### What happens if a GitHub user has no email or Gravatar configured?

The templates use Mustache sections (e.g., `{{#email}}...{{/email}}`) to conditionally render content. If the `email` or `gravatar_id` properties are missing or empty in the `view` object, those sections are omitted from the final HTML output, preventing broken links or empty elements. This logic-less conditional rendering ensures the résumé displays only available information.