The home for competitive debate. Discover upcoming debate tournaments from around the world with a modern, intuitive interface.
Live at: debatecomps.com
DebateComps is a curated tournament discovery platform for the global debate community. Whether you're a debater looking for your next competition, an adjudicator searching for judging opportunities, or an organizer promoting your tournament, DebateComps makes it easy to find and share debate competitions.
Data is sourced from multiple community-managed Google Sheets:
- Global Debating Spreadsheet (GDS) - International tournaments
- CUSID University Schedule - Canadian tournaments
- Indian Debating Spreadsheet (IDS) - Indian tournaments
- 🌍 Multi-Source Tournament Directory - Browse tournaments from Global, Canada, and India sources via a config-driven architecture
- 🏳️ Country Toggle - Switch between sources using the header dropdown with SVG flag icons
- 📅 Dual View Modes - Switch between grid and calendar views
- 🔍 Advanced Filtering - Filter by location (online/in-person), format, team cap, category, timezone proximity, and more
- ⏪ Past Tournaments - Collapsible section for past tournaments with automatic date-based splitting
- 🔄 Live Data - Auto-updates from multiple community-managed spreadsheets
- 💾 Save Tournaments - Bookmark tournaments across all sources; saved page fetches and deduplicates from every source
- 🌙 Dark Mode - Complete dark mode support with theme persistence
- ⚡ Smart Caching - 1-hour server caching for optimal performance
- 📱 Mobile Responsive - Fully responsive design for all devices
- 🔄 Manual Refresh - One-click refresh to bypass cache when needed
The app uses a config-driven approach to multi-source tournament fetching. Each data source (Global, Canada, India) is defined as a SourceConfig object in src/lib/sources.ts that specifies:
- Google Sheet ID and range formulas (with dynamic year derivation)
- Header detection strategy and column-to-field mapping
- Field transforms, defaults, and post-processing hooks
- Category color mappings for row classification
- Optional stateful iteration (e.g., Canada's month-header rows)
A single fetchTournaments(sourceId) function in src/lib/fetch-tournaments.ts handles all sources via these configs, eliminating per-source route files.
- Config-Driven Sources - Each source is a
SourceConfiginsrc/lib/sources.tspointing to a community-managed Google Sheet - Unified API -
GET /api/tournaments?source=global|india|canadadispatches to the shared fetch logic - Smart Caching - Responses are cached for 1 hour (
s-maxage=3600, stale-while-revalidate=86400) - Dynamic Routing -
src/app/[source]/page.tsxrenders the sharedTournamentsPagecomponent for each source - Past/Upcoming Split - Tournaments are automatically split into upcoming and past sections based on end dates
To add a tournament to DebateComps:
- Open the appropriate spreadsheet (GDS for global, CUSID for Canada, IDS for India)
- Find the appropriate year tab (dynamically fetches current and next year)
- Fill in tournament information following the existing format in that sheet
- Click the refresh button on DebateComps to see your tournament immediately (or wait up to 1 hour)
To add a new regional source (e.g., UK tournaments):
- Add a new
SourceConfiginsrc/lib/sources.tswith the sheet ID, column mappings, and any field transforms - Add it to
SOURCE_CONFIGSandSOURCE_LIST - No new route files or API changes needed -- the existing
/api/tournaments?source=<id>and[source]/page.tsxhandle it automatically
- Default: Data is cached for 1 hour on the server
- Manual Refresh: Click the refresh icon to bypass cache and fetch latest data immediately
- Stale-While-Revalidate: After 1 hour, the cache refreshes in the background for seamless updates
- Framework: Next.js 15 with React 19
- Styling: Tailwind CSS 4
- UI Components: Radix UI
- Calendar: React Big Calendar
- Icons: Lucide React
- Flags: flag-icons (SVG country flags)
- Data Source: Google Sheets API
- Linting: Biome
- Analytics: Vercel Analytics
- Node.js 18+
- npm or yarn
# Clone the repository
git clone https://github.com/yourusername/debatecomps.git
cd debatecomps
# Install dependencies
npm install
# Set up environment variables
cp .env.example .env.local
# Add your SHEETS_API_KEY to .env.local# Start development server with Turbopack
npm run dev
# Open http://localhost:3000 in your browsernpm run build
npm start# Lint and format code
npm run lint
npm run formatsrc/
├── app/
│ ├── page.tsx # Home page (renders TournamentsPage with source="global")
│ ├── [source]/page.tsx # Dynamic source routes (/india, /canada)
│ ├── about/page.tsx # About page
│ ├── saved/page.tsx # Saved tournaments (multi-source fetch + dedup)
│ ├── api/tournaments/route.ts # Unified API endpoint (?source=global|india|canada)
│ ├── layout.tsx # Root layout with theme provider
│ └── globals.css # Global styles and theme
├── components/
│ ├── custom/
│ │ ├── tournaments-page.tsx # Shared page component for all sources
│ │ ├── site-header.tsx # Header with logo, nav, and country toggle
│ │ ├── country-toggle.tsx # Source switcher dropdown with flag icons
│ │ ├── search-filter-bar.tsx # Search and filter controls
│ │ ├── event-card.tsx # Tournament card component
│ │ ├── past-section.tsx # Collapsible past tournaments section
│ │ ├── calendar-view.tsx # Calendar view component
│ │ ├── footer.tsx # Footer with source attribution links
│ │ └── theme-toggle.tsx # Dark mode toggle
│ └── ui/ # Radix UI component wrappers
├── lib/
│ ├── sources.ts # Source configs (sheet IDs, header maps, transforms)
│ ├── fetch-tournaments.ts # Config-driven Google Sheets fetcher
│ ├── sheets.ts # Shared Sheets API cell extraction helpers
│ ├── use-past-upcoming.ts # Hook to split tournaments by date
│ ├── theme-provider.tsx # Dark mode context and logic
│ ├── utils.ts # Utility functions
│ └── ... # Other utilities (timezone, calendar-export, etc.)
└── types/
└── tournament.ts # TypeScript types
SHEETS_API_KEY=your_google_sheets_api_key
DebateComps is built by and for the debate community. Contributions are welcome!
- Found a bug? Open an issue
- Have a feature idea? Start a discussion
- Want to improve the code? Submit a pull request
Browse tournaments in a card-based grid with essential information at a glance. Click any tournament card to see full details.
Visualize tournaments on a calendar. Available in month, week, day, and agenda views. Color-coded by type (online/in-person).
- Search by tournament name or location
- Filter by format (BP, AP, Other)
- Filter by type (online/in-person)
- Filter by category (Premier Regional, Large, WUDC)
- Filter by timezone proximity (same, close, far)
- Filter by team capacity range
- One-day only toggle
Bookmark tournaments for later. The saved page fetches from all sources and deduplicates by competition name and date. Tournaments are stored locally in your browser.
Tournaments whose end date has passed are automatically moved to a collapsible "Past" section at the bottom of both the main page and saved page.
Toggle between light and dark themes. Your preference is saved automatically.
- Smart Caching: 1-hour server-side caching reduces API calls
- Optimized Images: Next.js Image optimization for logo and assets
- Vercel Deployment: Global CDN for fast content delivery
- Code Splitting: Automatic code splitting for optimal page loads
- Chrome/Edge (latest)
- Firefox (latest)
- Safari (latest)
- Mobile browsers (iOS Safari, Chrome Mobile)
This project is open source and available under the MIT License.
- Creators: Alex Zhu, Aditya Keerthi, Barton Lu, Advait Sangle, Acon Lin
- Data Management: Senkai Hsia and Claire Beamer (Global Debating Spreadsheet)
- Community: The global debate community for tournament data and feedback
For questions, issues, or suggestions:
- Open an issue on GitHub
- Reach out to Alex on Facebook or Discord
Made with ❤️ for the debate community