A minimal web app that lets guests queue songs to a Spotify playback session. Search for tracks, add them to the host's queue, and see what's playing β no Spotify account needed for guests.
Everything runs on Vercel (static frontend + serverless API + Upstash Redis). There is no separate backend, no database to manage, and no login for guests. The host configures everything through an in-app setup wizard on first visit. It deploys entirely from GitHub β no local Node.js installation required.
- Search β Find songs via Spotify's catalog
- Queue β Add tracks to the host's active Spotify queue
- Now Playing β See the current track and upcoming queue
- In-app setup wizard β Connect Spotify and customize the party right in the browser
- Party theming β Custom event name, emoji, and accent color
- No guest login β Share one link, guests just start queuing
ββββββββββββββββ ββββββββββββββββββββ ββββββββββββββββ
β React SPA ββββββΆβ Vercel API ββββββΆβ Spotify API β
β (Vercel) β β Routes (/api/*) β β (Web API) β
ββββββββββββββββ ββββββββββββββββββββ ββββββββββββββββ
β
ββββββββ΄βββββββ
β Upstash β
β Redis β
β creds + β
β party configβ
βββββββββββββββ
| Layer | Technology |
|---|---|
| Frontend | React 19, TypeScript, Tailwind CSS 4, Vite |
| State | TanStack React Query |
| Backend | Vercel Serverless Functions (/api) |
| Storage | Upstash Redis (via Vercel Marketplace) |
| Hosting | Vercel |
| External API | Spotify Web API |
This project deploys entirely in the cloud. You never install Node, pnpm, or any CLI β Vercel clones the repo, installs dependencies, builds, and hosts the API + frontend for you. Every push to GitHub redeploys automatically.
This points at
patrickdomnick/spotify-queue. To deploy your own copy, fork the repo and swap the username in the URL.
The button forks the repo into your GitHub account and creates the Vercel project.
- Fork this repo (GitHub "Fork" button β browser only).
- Go to vercel.com/new, pick the forked repo, and click Deploy. Vercel auto-detects the Vite + pnpm setup and builds in the cloud.
- Add a Redis store β In your new project, open Storage β Create Database, choose Upstash (Redis) from the Marketplace, and connect it. This auto-injects the
KV_REST_API_URL/KV_REST_API_TOKENenv vars. Redeploy if prompted. - Open your app URL β You'll be greeted by the setup wizard.
- Follow the wizard β Create a Spotify app, connect it, name your party. Done.
No environment variables to set by hand, no terminal commands, no local toolchain. See docs/vercel-setup.md for the detailed walkthrough.
On first visit (before setup is complete) the app shows a 3-step wizard:
- Spotify credentials β The wizard shows you the exact Redirect URI to paste into a new Spotify app. You paste back the Client ID + Secret. See docs/spotify-setup.md.
- Connect Spotify β One click sends you to Spotify to authorize the host (Premium) account, then back to the app. The refresh token is stored in Redis.
- Party theming β Set the event name, emoji, accent color, and an optional admin PIN that locks the settings afterward.
After setup, guests visiting the same URL see the queue directly. To reconfigure later, visit /?admin=1 (or tap β in the header) and enter the admin PIN.
- Node.js 22+
- pnpm 10+
- A Spotify Premium account
- (For full-stack local testing) the Vercel CLI and a linked Redis store
pnpm install
pnpm devpnpm dev runs Vite at http://localhost:5173. Note: the /api routes are not served by Vite, so search/queue calls won't work in this mode β it's for UI iteration only.
npm i -g vercel
vercel link # link to your Vercel project
vercel env pull .env.local # pulls Redis credentials locally
pnpm dev:vercel # runs `vercel dev` β serves frontend + /api togetherapi/
βββ _lib/
β βββ config.ts # Redis config store (creds + party + pin)
β βββ kv.ts # Lazy Upstash Redis client (env-agnostic)
β βββ spotify.ts # Token refresh + OAuth code exchange
β βββ auth.ts # Admin PIN hashing + setup-access gate
β βββ http.ts # Request origin / redirect URI helpers
βββ config.ts # GET public party config
βββ spotify/
β βββ search.ts # GET ?q= β tracks
β βββ queue.ts # POST { uri } β add to queue
β βββ queue-list.ts # GET β now playing + queue
βββ setup/
βββ status.ts # GET setup state + redirect URI
βββ credentials.ts # POST Spotify client id/secret
βββ connect.ts # GET β redirect to Spotify OAuth
βββ callback.ts # GET OAuth callback β store refresh token
βββ finalize.ts # POST party theming + finish setup
βββ verify-pin.ts # POST β validate admin PIN
βββ reset.ts # POST β reopen setup (admin only)
src/
βββ main.tsx
βββ App.tsx # Config gate: wizard vs party UI
βββ index.css
βββ lib/
β βββ config.ts # /api/config + /api/setup client + theming
β βββ spotify.ts # /api/spotify client
βββ hooks/
β βββ useConfig.ts # Public config query
β βββ useSpotify.ts # Search, queue, queue-list hooks
βββ components/
βββ SetupWizard.tsx # 3-step setup flow
βββ Header.tsx # Party name/emoji + settings gear
βββ SearchBar.tsx
βββ TrackRow.tsx
βββ NowPlaying.tsx
βββ QueueView.tsx
tests/
βββ api/ # auth, config, http, spotify (mocked KV/fetch)
βββ lib/ # frontend spotify + config clients (mocked fetch)
| Command | Description |
|---|---|
pnpm dev |
Vite dev server (frontend only) |
pnpm dev:vercel |
vercel dev β frontend + API routes |
pnpm build |
TypeScript check + production build |
pnpm preview |
Preview production build locally |
pnpm lint |
Biome check |
pnpm lint:fix |
Biome auto-fix |
pnpm type-check |
Type-check the frontend |
pnpm type-check:api |
Type-check the API functions |
pnpm test |
Run the unit test suite (Vitest) |
pnpm test:watch |
Run tests in watch mode |
| Variable | Where | Notes |
|---|---|---|
KV_REST_API_URL |
Auto-injected by the Redis integration | Pull locally with vercel env pull |
KV_REST_API_TOKEN |
Auto-injected by the Redis integration | Pull locally with vercel env pull |
Spotify credentials are entered through the setup wizard and stored in Redis β they are never set as environment variables.
- Guest opens the app β if configured, sees the party queue directly (no login).
- Searches for a song β debounced search via
/api/spotify/searchβ Spotify Search API. - Clicks "Add" β
/api/spotify/queueadds the track to the host's active device. - Queue refreshes β shows updated "Now Playing" and upcoming tracks.
The host just needs Spotify playing on any device (phone, laptop, speaker).
Unit tests run with Vitest:
pnpm test # run once
pnpm test:watch # watch modeCoverage focuses on the pure, high-value logic:
- API (
tests/api/) β admin PIN hashing/verification and the setup-access gate, request origin/redirect-URI derivation, the Spotify authorize-URL builder, token refresh + caching and OAuth code exchange (with KV andfetchmocked), and config defaults/merge/public-projection. - Frontend (
tests/lib/) β the/apiSpotify client and the config/setup client (withfetchmocked), plus accent-color theming.
The Spotify Web API and Redis are mocked, so no network or store is required.
- Guest endpoints are intentionally unauthenticated. Anyone with the URL can search and queue songs β this is by design for a shareable party link. Treat the URL as the access control; don't post it publicly if you don't want strangers queuing.
- Setup is locked after first run by an optional admin PIN (salted scrypt hash in Redis). Without a PIN, anyone could re-run setup, so setting one is recommended.
- Spotify secrets (client secret, refresh token) live in Redis and are never exposed to the client β only the public party theming is sent to the browser.
- Spotify Premium required on the host account
- Active playback required β queue fails if nothing is playing
- Rate limits β ~180 Spotify API calls/minute (plenty for a party)
- Upstash Redis free tier β generous for a party app
- Vercel free tier β 100GB bandwidth/month
MIT