In today's development landscape, integrating with GitHub's API is essential for building developer tools, project management dashboards, and automation workflows. However, creating a robust, type-safe, and user-friendly GitHub integration from scratch can be time-consuming and error-prone.
This template provides a complete, production-ready GitHub integration built with Next.js 15, TypeScript, and Tambo AI. It demonstrates how to create intelligent, conversational interfaces for GitHub data while maintaining clean architecture and solid engineering principles.
🔍 Smart GitHub Data Retrieval
- List organization repositories with sorting and filtering
- Fetch repository issues with state management
- Retrieve pull requests with detailed metadata
- Natural language intent resolution for GitHub queries
🎨 Beautiful UI Components
- Responsive repository cards with key metrics
- Interactive issue and PR cards with status indicators
- Clean, modern design using Tailwind CSS
- Accessible components following best practices
🤖 AI-Powered Interactions
- Natural language processing for GitHub queries
- Intelligent intent resolution ("Show me React issues" → API calls)
- Conversational interface powered by Tambo AI
- Context-aware responses and suggestions
⚡ Production-Ready Architecture
- Type-safe API layer with Zod validation
- Modular service architecture
- Error handling and loading states
- Optimized for performance and scalability
The template follows a clean, layered architecture:
src/
├── app/ # Next.js app router pages
├── components/
│ ├── ui/ # Reusable UI components
│ └── tambo/ # Tambo AI integration components
├── lib/
│ ├── tambo.ts # Tambo configuration and tools
│ ├── types.ts # TypeScript type definitions
│ └── utils.ts # Utility functions
└── services/
├── github-api.ts # GitHub API client
├── github-tools.ts # GitHub tool implementations
└── resolve-github-intent.ts # Intent resolution logic
A robust, type-safe wrapper around GitHub's REST API:
class GitHubAPI {
async getRepositoryIssues({
owner,
repo,
state = "all",
per_page = 30
}: IssuesInput): Promise<GitHubIssue[]> {
// Implementation with error handling and type validation
}
}Key Features:
- Automatic error handling with custom error types
- Request/response validation using Zod schemas
- Rate limiting awareness
- Configurable authentication
Transforms natural language queries into structured API calls:
export async function resolveGitHubIntent(
input: string,
fallback_per_page: number = 4
): Promise<GitHubIntent> {
// Uses AI to parse queries like:
// "Show me open issues in facebook/react"
// → { kind: "list_issues", params: { owner: "facebook", repo: "react", state: "open" }}
}Reusable, accessible components for displaying GitHub data:
- RepoCard: Repository information with stars, forks, and language
- IssueCard: Issue details with labels, assignees, and status
- PRCard: Pull request information with merge status and reviews
Configures Tambo AI tools and components for the GitHub integration:
export const tools: TamboTool[] = [
{
name: "resolveGitHubIntent",
description: "Resolve GitHub-related queries into structured intents",
toolSchema: z.object({
input: z.string().describe("Natural language GitHub query"),
fallback_per_page: z.number().optional()
}),
implementation: resolveGitHubIntent
},
// Additional tools...
];- Node.js 18+ or Bun
- GitHub Personal Access Token
- Tambo AI account (for AI features)
-
Clone and Install
git clone <repository-url> cd tambo-github bun install # or npm install
-
Environment Configuration
cp .env.example .env
Add your credentials:
GITHUB_TOKEN=your_github_token_here NEXT_PUBLIC_TAMBO_API_KEY=your_NEXT_PUBLIC_TAMBO_API_KEY_here
-
Run Development Server
bun dev # or npm run dev -
Test the Integration
- Visit
http://localhost:3000/test-github - Try the example queries:
- "List repositories for vercel organization"
- "Show me issues in facebook/react"
- "Get pull requests for microsoft/vscode"
- Visit
- Go to GitHub Settings → Developer settings → Personal access tokens
- Generate a new token with these scopes:
public_repo(for public repositories)repo(for private repositories, if needed)read:org(for organization data)
- Sign up at Tambo AI
- Create a new project
- Copy your API key to the
.envfile
-
Define Types (
src/lib/types.ts):export const githubCommitSchema = z.object({ sha: z.string(), commit: z.object({ message: z.string(), author: z.object({ name: z.string(), date: z.string() }) }) });
-
Add API Method (
src/services/github-api.ts):async getRepositoryCommits({ owner, repo, per_page = 30 }) { const data = await this.request(`/repos/${owner}/${repo}/commits`); return data.map(item => githubCommitSchema.parse(item)); }
-
Create Tool Wrapper (
src/services/github-tools.ts):export async function getRepositoryCommits(input: CommitsInput) { return githubAPI.getRepositoryCommits(input); }
-
Register with Tambo (
src/lib/tambo.ts):{ name: "getRepositoryCommits", description: "Get commits for a repository", toolSchema: commitsInputSchema, implementation: getRepositoryCommits }
-
Component Structure:
interface CommitCardProps { commit: GitHubCommit; onClick?: () => void; } export function CommitCard({ commit, onClick }: CommitCardProps) { return ( <Card className="cursor-pointer hover:shadow-md transition-shadow"> {/* Component implementation */} </Card> ); }
-
Register with Tambo:
export const components: TamboComponent[] = [ { name: "CommitCard", component: CommitCard, description: "Display GitHub commit information" } ];
Add new intent types by modifying the intent resolution logic:
// Add new intent type
type GitHubIntent =
| { kind: "list_repos"; params: { org: string } }
| { kind: "list_commits"; params: { owner: string; repo: string } }
| // existing intents...
// Update resolution logic
if (input.includes("commits")) {
return {
kind: "list_commits",
params: { owner: extractedOwner, repo: extractedRepo }
};
}-
Implement Caching:
const cache = new Map(); async function getCachedRepositories(org: string) { const key = `repos:${org}`; if (cache.has(key)) return cache.get(key); const data = await getOrganizationRepositories(org); cache.set(key, data); return data; }
-
Use React Query for data fetching:
const { data, isLoading, error } = useQuery({ queryKey: ['repos', org], queryFn: () => getOrganizationRepositories(org), staleTime: 5 * 60 * 1000 // 5 minutes });
-
Graceful Degradation:
try { const issues = await getRepositoryIssues(params); return issues; } catch (error) { if (error.status === 404) { return { error: "Repository not found" }; } throw error; }
-
User-Friendly Error Messages:
const errorMessages = { 401: "Please check your GitHub token", 403: "Rate limit exceeded. Please try again later", 404: "Repository or organization not found" };
- Environment Variables: Never commit tokens to version control
- Rate Limiting: Implement client-side rate limiting
- Input Validation: Always validate user inputs
- CORS: Configure properly for production deployment
- Connect your GitHub repository to Vercel
- Add environment variables in Vercel dashboard
- Deploy automatically on push
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
RUN npm run build
EXPOSE 3000
CMD ["npm", "start"]This GitHub integration template provides a solid foundation for building sophisticated developer tools and GitHub-powered applications. The combination of type safety, clean architecture, and AI-powered interactions makes it easy to create powerful, user-friendly experiences.
Key takeaways:
- Type safety prevents runtime errors and improves developer experience
- Modular architecture makes the codebase maintainable and extensible
- AI integration enables natural language interactions with GitHub data
- Production-ready patterns ensure scalability and reliability
Whether you're building a project dashboard, developer tool, or automation platform, this template gives you everything you need to go from concept to production quickly and confidently.
- GitHub API Documentation
- Tambo AI Documentation
- Next.js Documentation
- TypeScript Handbook
- Tailwind CSS Documentation
Ready to build something amazing? Clone the repository and start exploring the possibilities!