Phaser
30 minutes
linux
macos
windows

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:

bash
npm 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:

bash
npm run preview

Open http://localhost:4173 and verify everything works.

Deployment Options

PlatformCostBest For
GitHub PagesFreeSimple games, portfolios
NetlifyFree tierAutomatic deploys
VercelFree tierFast CDN
itch.ioFreeGame distribution, sales
Cloudflare PagesFreeFast global CDN

GitHub Pages

Free hosting directly from your repository.

Step 1: Prepare Build

Update vite.config.ts:

typescript
import { 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:

yaml
name: 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

  1. Go to repository Settings → Pages
  2. Set Source to "gh-pages" branch
  3. 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

  1. Run npm run build
  2. Go to app.netlify.com
  3. Drag your dist folder onto the page
  4. Done! You get a URL instantly.

Option 2: Git Integration

  1. Push to GitHub/GitLab
  2. Connect repository on Netlify
  3. Set build command: npm run build
  4. Set publish directory: dist
  5. 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

  1. Import project on vercel.com
  2. Configure:
    • Build command: npm run build
    • Output directory: dist
  3. Deploy!

itch.io

Popular platform for indie game distribution.

Upload Your Game

  1. Create account at itch.io
  2. Click "Dashboard" → "Create new project"
  3. Select "HTML" as the kind of project
  4. Set embed dimensions (800x600 or your game size)
  5. Zip your dist folder
  6. Upload the zip file
  7. Check "This file will be played in the browser"
  8. 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 TypeToolSavings
ImagesTinyPNG, ImageOptim50-80%
AudioAudacity (export at lower bitrate)50%+
JSONMinify30%

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

typescript
const 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:

typescript
create(): 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:

bash
npm 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:

  1. Base path is correct in vite.config.ts
  2. Asset paths are relative or use correct base
  3. Assets are in the public folder
  4. Case sensitivity (Linux servers are case-sensitive)

Use Phaser's scale manager:

typescript
scale: {
  mode: Phaser.Scale.FIT,
  autoCenter: Phaser.Scale.CENTER_BOTH,
}

Mobile requires user interaction to play audio. Start audio after a tap:

typescript
this.input.once('pointerdown', () => {
  this.sound.play('music');
});
  1. Reduce sprite counts
  2. Use sprite sheets instead of individual images
  3. Lower resolution graphics
  4. Disable debug mode
  5. Simplify physics calculations

Deployment Checklist

Before publishing:

  • Removed debug: true from 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:

0/5

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!