Back to blog

How to build a custom Minecraft launcher for your server

Building a custom launcher is the best way to ensure your players always have the right version and settings. With EML Lib, this process is now accessible to everyone.

This guide walks you through building a minimal Electron launcher using the Agnostic mode (standalone), which doesn’t require any complex backend infrastructure.

Prerequisites

  • Node.js v20+
  • Basic JavaScript knowledge

Step 1: Initialize the project

mkdir my-launcher && cd my-launcher
npm init -y
npm install eml-lib electron

Step 2: The UI (index.html)

Create an index.html file. We keep it simple: a field for the player name and a “Play” button.

<!DOCTYPE html>
<html>
  <head>
    <title>EML Demo Launcher</title>
    <style>
      body {
        background: #1a1a1a;
        color: white;
        font-family: sans-serif;
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        height: 100vh;
        margin: 0;
      }
      input {
        padding: 10px;
        margin-bottom: 10px;
        border-radius: 4px;
        border: none;
        width: 200px;
      }
      button {
        padding: 10px 20px;
        background: #388e3c;
        color: white;
        border: none;
        border-radius: 4px;
        cursor: pointer;
      }
      #status {
        margin-top: 20px;
        font-size: 0.9em;
        color: #888;
      }
    </style>
  </head>
  <body>
    <h1>Minecraft Launcher</h1>
    <input type="text" id="username" placeholder="Player Name" value="Player" />
    <button id="play-btn">PLAY</button>
    <div id="status">Ready to launch</div>

    <script>
      const { ipcRenderer } = require('electron')
      const playBtn = document.getElementById('play-btn')
      const status = document.getElementById('status')

      playBtn.addEventListener('click', () => {
        const name = document.getElementById('username').value
        status.innerText = 'Launching...'
        playBtn.disabled = true
        ipcRenderer.send('launch-game', name)
      })

      ipcRenderer.on('log', (event, msg) => {
        status.innerText = msg
      })
    </script>
  </body>
</html>

Step 3: The main process (main.js)

This is where EML Lib does the magic. Create a main.js file.

const { app, BrowserWindow, ipcMain } = require('electron')
const { Launcher, CrackAuth } = require('eml-lib')
const path = require('path')

function createWindow() {
  const win = new BrowserWindow({
    width: 400,
    height: 500,
    webPreferences: {
      nodeIntegration: true,
      contextIsolation: false
    }
  })
  win.loadFile('index.html')
  return win
}

app.whenReady().then(() => {
  const mainWindow = createWindow()

  ipcMain.on('launch-game', async (event, username) => {
    const auth = new CrackAuth()
    const account = auth.auth(username)

    const launcher = new Launcher({
      root: path.join(app.getPath('userData'), 'game'),
      account: account,
      minecraft: {
        version: '1.20.4'
      }
    })

    launcher.on('launch_download', (d) => mainWindow.webContents.send('log', `Downloading ${d.total.amount} files...`))
    launcher.on('launch_launch', () => mainWindow.webContents.send('log', 'Opening Minecraft...'))
    launcher.on('launch_close', () => app.quit())

    try {
      await launcher.launch()
    } catch (err) {
      mainWindow.webContents.send('log', 'Error: ' + err.message)
    }
  })
})

Note

The CrackAuth is used here for simplicity. For a real server, you should use MicrosoftAuth (or any other authentication method provided by EML Lib) to ensure players have a valid license.

Tip

  • This example uses the Agnostic mode (standalone), which means it doesn’t require any backend server. But you can easily connect it to the EML AdminTool later to manage your mods and configs remotely without updating the launcher itself.
  • To help you configure you launcher, you can use Config generator to generate the Launcher options based on your needs.

Step 4: Run it!

Update your package.json to include "main": "main.js" juste under the "name" field and run:

npx electron .

Key takeaways

  • Authentication: We used CrackAuth for simplicity. For a real server, you should use MicrosoftAuth to ensure players have a valid license.
  • Agnostic mode: Introduced in v2.2.0, it allows you to launch Minecraft (Vanilla or Modded) without any backend server.
  • Scalability: While this script is standalone, you can easily connect it to the EML AdminTool later to manage your mods and configs remotely without updating the launcher itself.

The full API documentation is available on here. Happy coding!