Building and Deploying
Build your Phaser game for production and deploy it to various hosting platforms.
What you'll accomplish
Deploy a production-ready Phaser game to the web.
Prerequisites
- Complete Phaser game
- Basic understanding of web hosting
Production Build
Build your game for production:
bashnpm run build
This creates a dist folder with optimized files:
dist/
├── index.html
├── assets/
│ ├── index-[hash].js # Your game code (minified)
│ └── index-[hash].css # Styles (if any)
└── (your assets)
Test Production Build
Before deploying, test locally:
bashnpm run preview
Open http://localhost:4173 and verify everything works.
Deployment Options
| Platform | Cost | Best For |
|---|---|---|
| GitHub Pages | Free | Simple games, portfolios |
| Netlify | Free tier | Automatic deploys |
| Vercel | Free tier | Fast CDN |
| itch.io | Free | Game distribution, sales |
| Cloudflare Pages | Free | Fast global CDN |
GitHub Pages
Free hosting directly from your repository.
Step 1: Prepare Build
Update vite.config.ts:
typescriptimport { defineConfig } from 'vite'; export default defineConfig({ base: '/your-repo-name/', // Repository name build: { outDir: 'dist', }, });
Step 2: Create GitHub Workflow
Create .github/workflows/deploy.yml:
yamlname: Deploy to GitHub Pages on: push: branches: [main] jobs: build-and-deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Setup Node uses: actions/setup-node@v4 with: node-version: '20' - name: Install dependencies run: npm ci - name: Build run: npm run build - name: Deploy to GitHub Pages uses: peaceiris/actions-gh-pages@v3 with: github_token: ${{ secrets.GITHUB_TOKEN }} publish_dir: ./dist
Step 3: Enable GitHub Pages
- Go to repository Settings → Pages
- Set Source to "gh-pages" branch
- Wait for deployment
Your game is live at: https://yourusername.github.io/your-repo-name/
Netlify
Simple drag-and-drop or Git-connected deployment.
Option 1: Drag and Drop
- Run
npm run build - Go to app.netlify.com
- Drag your
distfolder onto the page - Done! You get a URL instantly.
Option 2: Git Integration
- Push to GitHub/GitLab
- Connect repository on Netlify
- Set build command:
npm run build - Set publish directory:
dist - Deploy!
Create netlify.toml for configuration:
toml[build] command = "npm run build" publish = "dist" [[redirects]] from = "/*" to = "/index.html" status = 200
Vercel
Similar to Netlify with great performance.
Deploy with CLI
bash# Install Vercel CLI npm install -g vercel # Deploy vercel # Production deploy vercel --prod
Deploy with Git
- Import project on vercel.com
- Configure:
- Build command:
npm run build - Output directory:
dist
- Build command:
- Deploy!
itch.io
Popular platform for indie game distribution.
Upload Your Game
- Create account at itch.io
- Click "Dashboard" → "Create new project"
- Select "HTML" as the kind of project
- Set embed dimensions (800x600 or your game size)
- Zip your
distfolder - Upload the zip file
- Check "This file will be played in the browser"
- Publish!
itch.io Configuration
Recommended settings:
- Embed in page (not external link)
- Set correct dimensions
- Enable fullscreen button
- Add cover image (630x500)
- Write compelling description
Monetization on itch.io
Options:
- Free download
- Pay what you want
- Fixed price
- Donations
Optimizing for Production
Reduce Bundle Size
typescript// Import only what you need import Phaser from 'phaser'; // Instead of importing everything // import * as Phaser from 'phaser';
Compress Assets
| Asset Type | Tool | Savings |
|---|---|---|
| Images | TinyPNG, ImageOptim | 50-80% |
| Audio | Audacity (export at lower bitrate) | 50%+ |
| JSON | Minify | 30% |
Asset Loading Screen
Show loading progress:
typescript// BootScene.ts preload(): void { // Create loading bar const progressBar = this.add.graphics(); const progressBox = this.add.graphics(); progressBox.fillStyle(0x222222, 0.8); progressBox.fillRect(240, 270, 320, 50); // Update progress this.load.on('progress', (value: number) => { progressBar.clear(); progressBar.fillStyle(0xffffff, 1); progressBar.fillRect(250, 280, 300 * value, 30); }); this.load.on('complete', () => { progressBar.destroy(); progressBox.destroy(); this.scene.start('MenuScene'); }); // Load all assets this.load.image('player', 'assets/player.png'); // ... more assets }
Mobile Optimization
typescriptconst config: Phaser.Types.Core.GameConfig = { scale: { mode: Phaser.Scale.FIT, autoCenter: Phaser.Scale.CENTER_BOTH, width: 800, height: 600, }, input: { touch: true, // Enable touch }, };
Add touch controls:
typescriptcreate(): void { // Touch areas const leftZone = this.add.zone(0, 0, 400, 600) .setOrigin(0, 0) .setInteractive(); const rightZone = this.add.zone(400, 0, 400, 600) .setOrigin(0, 0) .setInteractive(); leftZone.on('pointerdown', () => this.moveLeft = true); leftZone.on('pointerup', () => this.moveLeft = false); rightZone.on('pointerdown', () => this.moveRight = true); rightZone.on('pointerup', () => this.moveRight = false); }
PWA Support
Make your game installable as an app:
1. Create manifest.json
json{ "name": "My Phaser Game", "short_name": "Game", "description": "An awesome game built with Phaser", "start_url": "/", "display": "fullscreen", "background_color": "#000000", "theme_color": "#000000", "icons": [ { "src": "/icon-192.png", "sizes": "192x192", "type": "image/png" }, { "src": "/icon-512.png", "sizes": "512x512", "type": "image/png" } ] }
2. Add to HTML
html<link rel="manifest" href="/manifest.json"> <meta name="theme-color" content="#000000">
3. Register Service Worker
typescript// main.ts if ('serviceWorker' in navigator) { navigator.serviceWorker.register('/sw.js'); }
Capacitor for Mobile
Wrap your Phaser game as a native app:
bashnpm install @capacitor/core @capacitor/cli npx cap init # Update capacitor.config.ts # webDir: 'dist' npm run build npx cap add android npx cap add ios npx cap sync npx cap open android # or ios
See the Capacitor track for full mobile deployment.
Common Issues
Frequently Asked Questions
Check:
- Base path is correct in
vite.config.ts - Asset paths are relative or use correct base
- Assets are in the
publicfolder - Case sensitivity (Linux servers are case-sensitive)
Use Phaser's scale manager:
typescriptscale: { mode: Phaser.Scale.FIT, autoCenter: Phaser.Scale.CENTER_BOTH, }
Mobile requires user interaction to play audio. Start audio after a tap:
typescriptthis.input.once('pointerdown', () => { this.sound.play('music'); });
- Reduce sprite counts
- Use sprite sheets instead of individual images
- Lower resolution graphics
- Disable debug mode
- Simplify physics calculations
Deployment Checklist
Before publishing:
- Removed
debug: truefrom physics config - Tested on target browsers/devices
- Optimized and compressed assets
- Added loading screen
- Included mute/sound controls
- Set correct game dimensions
- Added favicon and meta tags
- Tested production build locally
Track Complete!
You've completed the Phaser track if you can:
Congratulations! You've completed the Phaser track. You now have the skills to create and deploy 2D browser games. Keep building and share your creations!