---
title: "Headless PreForm Server"
description: "Install PreForm Server, PreForm without its window, and start it from the Python SDK to run scripts headless."
url: https://developer.formlabs.com/guides/headless-preform-server/
---

# Headless PreForm Server

PreForm Server is PreForm without its user interface. It serves the same PreForm API, so a
script written against PreForm runs unchanged against PreForm Server. Use it where no
one watches the screen, such as a computer that prepares each incoming order as it
arrives, or an application that runs as a service.

Most scripts don't need PreForm Server: get started [by connecting to the PreForm window](https://developer.formlabs.com/getting-started/install.md#connect-to-a-running-preform)
you already have open.

## Download PreForm Server

PreForm Server is distributed separately from PreForm. Download the build for macOS
or Windows from
[Formlabs API downloads and release notes](https://formlabs.com/support/Formlabs-API-downloads-and-release-notes?language=en_US).

The SDK starts the server from the path of its executable. On macOS, that's the
executable inside the app bundle, because the `.app` folder itself isn't an
executable.

## Start PreForm Server from Python

To check the setup, start the server, print its version, and shut it down:

```python
import os

from formlabs_sdk import FormlabsClient

# On macOS, set PREFORM to the executable inside PreFormServer.app.
PREFORM = os.environ.get("PREFORM", "PreFormServer.exe")

with FormlabsClient() as client:
    # launch() waits up to 60 seconds for the server to start. Leaving the with block
    # shuts the server down.
    with client.preform.launch(PREFORM) as preform:
        print(f"PreForm Server {preform.version} at {preform.base_url}")
```

The script prints the server version and `http://localhost:44388`. The `launch()`
method fails with `PORT_IN_USE` when another server already listens on port 44388. To
use another port, pass the `port` argument.

The SDK owns a server that `launch()` starts: leaving the `with` block shuts it down.
`launch()` also logs the server in with the client's account, when the client has
one. Every other call is the same as against PreForm, so a script from
[Create your first script](https://developer.formlabs.com/getting-started/quickstart.md) runs headless once `connect()` is
replaced with `launch()` and the path of the PreForm Server executable.

## Start PreForm Server from a terminal

PreForm Server also runs on its own. The `--port` argument is required:

**macOS:**

```bash
/Applications/PreFormServer.app/Contents/MacOS/PreFormServer --port 44388
```

**Windows:**

```powershell
C:\PreFormServer\PreFormServer.exe --port 44388
```

The server prints `READY FOR INPUT` after it starts accepting requests. A script then
attaches with the `connect()` method, exactly as it does to PreForm, and closing the
client leaves the server running. The `connect()` method leaves the server's login as
it is, so a server started this way stays logged out until it's logged in. For more
information, see [Log PreForm in](https://developer.formlabs.com/core-concepts/preform-client.md#log-preform-in).

For the other options, see [CLI & command-line options](https://developer.formlabs.com/resources/preform-server-cli.md).

## What's next

- [PreForm client](https://developer.formlabs.com/core-concepts/preform-client.md)
