Inspiration
Disc golf has exploded in popularity, but the tooling hasn’t kept up. Existing apps handle scorecards fine, but the rest of the sport — running a club, organizing events, tracking throws shot-by-shot, managing a bag of discs, finding and maintaining courses — lives scattered across spreadsheets, group chats, and paper. We wanted to build DG Tools: a single app that covers the entire life of a disc golfer, from casual rounds to running a league.
What it does
- Full round scoring — stroke play and match play, singles and doubles (with automatic "cali" teams for odd players), multiple scorecards, live leaderboards, and payouts at round summary.
- Shot tracking on a real map — place every throw on a Mapbox-powered satellite map, tag the disc used, rate the shot, record penalties, and review a shot map for every hole after the round.
- Course directory & management — browse nearby courses, create public/personal/private courses, build layouts hole-by-hole with tee/basket coordinates, fairway paths, mandos, and tee signs, and submit community corrections.
- Clubs & events — run clubs, schedule events, register players, and spin up rounds directly from an event.
- Social layer — friends, profiles with ratings distribution charts, group chat with polls, scorecard sharing, and message reactions.
- Disc inventory — bags and discs with flight characteristics that tie into shot tracking.
- Round Importing— a 4-step wizard to import historical scorecards so nobody starts from zero.
- Stats & marketplace — personal performance stats, a marketplace for discs, and premium subscriptions via Stripe.
How we built it
Frontend: React Native with Expo (SDK 57) and expo-router for file-based navigation. All UI is built on react-native-paper's theming system, with a custom ThemedText component and a shared component library for scorecards, chat bubbles, maps, and player pickers. Maps are powered by @rnmapbox/maps, charts and the tiled background by React Native Skia, and lists by Shopify's FlashList for smooth scrolling over large datasets.
Backend: Supabase — Postgres for the entire data model (rounds, scorecards, shots, courses, layouts, clubs, events, chat, inventory), Row Level Security for permissions, Storage for images and generated scorecard cards, and realtime for live scoring and chat presence. All data access flows through TanStack Query hooks so caching, optimistic updates, and invalidation are consistent across the app.
Payments & media: Stripe for premium subscriptions, Mux for video uploads, Branch for deep links, and Giphy because chat needs GIFs.
Challenges we ran into
- Shot editing UX on a map. Auto-fitting the camera to a whole hole made precise pin placement frustrating. We rebuilt it around a
focusOnShotmodel that zooms to the marker being placed while keeping the basket in frame — a small change that made the editor feel dramatically better. - Doubles match/stroke scoring edge cases. Odd player counts, multiple scorecards per round, and mixed formats meant the scoring engine and the DB schema had to handle teams as first-class entities rather than an afterthought.
- Data model breadth. Courses alone have layouts, holes, fairway geometry, mandos, ownership claims, and community-contributed corrections. Keeping the Postgres schema normalized while still queryable through TanStack Query required careful RPC design and seed data to test against.
- Migrating from Firebase to Supabase. Mid-project we moved off Firebase entirely to Postgres + RLS + TanStack Query, which meant rewriting every data-access layer — but resulted in a much stronger permission model and relational integrity.
What we learned
- Row Level Security is worth the upfront cost — it made multi-tenant features (private courses, club permissions, claimed layouts) dramatically safer.
- TanStack Query fundamentally changes React Native data fetching; optimistic updates made live scoring feel instant.
- Componentizing rendered items early paid off enormously — scorecards, chat bubbles, and map markers get reused across rounds, events, feeds, and profiles.
What's next
Deeper stats (strokes-gained style analytics off shot-tracking data), live round spectating, and expanding the marketplace.
Built With
- branch.io
- eas
- expo-router
- expo.io
- flash-list
- giphy
- javascript
- mux
- node.js
- postgresql
- react-native
- react-native-paper
- react-native-skia
- react-navigation
- rnmapbox
- shopify
- stripe
- supabase
- tanstack
- typescript
Log in or sign up for Devpost to join the conversation.