A self-hosted pomodoro timer with Spotify integration and a lofi aesthetic. Focus on your work while your favorite playlists play in the background.
- Timer presets: Short (15/3), Classic (25/5), Long (50/10)
- Overtime mode - timer counts up after completion, you decide when to switch
- Session statistics - track your focus time, streaks, and overtime
- Spotify integration with playlist selection
- Light/dark theme toggle
- Keyboard-first controls
- Go to Spotify Developer Dashboard
- Click "Create App"
- Fill in the details:
- App name: Spotify Pomodoro
- Redirect URI: See setup options below
- APIs used: Check "Web API"
- Copy the Client ID from your app's settings
Spotify allows HTTP only for localhost or 127.0.0.1. Use this for local testing:
# .env
PUBLIC_SPOTIFY_CLIENT_ID=your_client_id_here
PUBLIC_SPOTIFY_REDIRECT_URI=http://127.0.0.1:2500/callbackAdd http://127.0.0.1:2500/callback to your Spotify app's Redirect URIs.
For deployment on a server (Coolify, VPS, etc.), you need HTTPS. Set up a domain with SSL:
# .env
PUBLIC_SPOTIFY_CLIENT_ID=your_client_id_here
PUBLIC_SPOTIFY_REDIRECT_URI=https://pomodoro.yourdomain.com/callbackAdd https://pomodoro.yourdomain.com/callback to your Spotify app's Redirect URIs.
Note: Spotify requires HTTPS for any redirect URI that isn't
localhostor127.0.0.1. If deploying to a local network IP (e.g.,192.168.x.x), you must set up SSL via a reverse proxy or use a domain with DNS pointing to your server.
docker compose up -dOpen your configured URL in a browser.
docker compose pull
docker compose up -dYour session data persists in the pomodoro_data volume.
- Create a new service from this repository
- Set environment variables in Coolify's UI:
PUBLIC_SPOTIFY_CLIENT_IDPUBLIC_SPOTIFY_REDIRECT_URI(use your Coolify domain:https://pomodoro.yourdomain.com/callback)
- Update your Spotify app's redirect URI to match
- Deploy
For VPS deployments, you can enable authentication to protect your instance:
# .env
AUTH_ENABLED=true
AUTH_PASSWORD=your-secure-password
AUTH_SECRET=random-32-character-string-for-signing- Username: Always
admin(pre-filled in login form for password manager compatibility) - Password: Your chosen password from
AUTH_PASSWORD - Secret: Any random string used for signing cookies (keep this secret!)
When enabled, all routes require login. The login page appears at /login.
Tip: Generate a secure secret with
openssl rand -base64 32
| Key | Action |
|---|---|
Space / Enter |
Start timer |
E |
End current session early (during countdown) |
S |
Skip to next phase (during overtime) |
R |
Reset timer (when stopped) |
See CONTRIBUTING.md for development setup.
# Without Docker
bun install
bun run db:migrate
bun run dev
# With Docker
docker compose -f docker-compose.dev.yml upSession data is stored in SQLite. When using Docker, data persists in the pomodoro_data volume.
To reset your data:
# Docker
docker compose down -v
docker compose up -d
# Local
bun run db:clean- Runtime: Bun
- Framework: Astro with React (SSR)
- Database: SQLite with Drizzle ORM
- Styling: Tailwind CSS v4 + shadcn/ui
- State Management: Effect-TS
Ensure the redirect URI in your Spotify app settings exactly matches PUBLIC_SPOTIFY_REDIRECT_URI in your environment.
Spotify requires an active device to control playback. Open Spotify on your computer or phone before selecting a playlist.
Check logs with docker compose logs. Ensure port 2500 is not in use by another service.
MIT