Recommendations¶
Security¶
Desktop App ID (appId) — recommended for all setups¶
Each Feather desktop app generates a unique App ID (a UUID stored in Settings). You must set one of the following in feather.config.lua — Feather will error at startup in socket mode if neither is present:
Option A — bind to your desktop app (recommended):
-- feather.config.lua
return {
-- Copy from Feather desktop app → Settings → Security → Desktop App ID
appId = "feather-app-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
}
The game rejects commands from any other Feather desktop instance. Only the matching app can control it.
Option B — explicit insecure opt-in:
-- feather.config.lua
return {
-- Any Feather desktop on the network can send commands to this game.
-- Set this only when you cannot use appId (e.g. shared dev machine, CI).
__DANGEROUS_INSECURE_CONNECTION__ = true,
}
Setting __DANGEROUS_INSECURE_CONNECTION__ = true is your acknowledgment that the game accepts commands from any Feather desktop on the network. Feather will not start without one of these two options — there is no silent fallback.
feather init prompts for the App ID during setup and writes it to feather.config.lua automatically. To find it: open the Feather desktop app → Settings → Security → Desktop App ID.
Note
appId identifies the desktop app instance, not a user or secret. If you reinstall or reset the desktop app, regenerate the App ID in Settings and update feather.config.lua.
appId prevents accidental cross-talk between development machines on the same network — it is not a cryptographic guarantee and is not a substitute for proper network isolation in shared or untrusted environments.
API Key (apiKey) — required only for the Console plugin¶
Set apiKey in the game config and match it in the Feather desktop app Settings. This gates access to the Console / REPL plugin (remote Lua execution):
Console plugin¶
Warning
Do not include the Console plugin in builds shipped to users. It allows remote code execution and can be a serious security risk.
MCP Access¶
Feather's MCP support is intended for local development automation. Keep Settings → Security → MCP Access disabled unless an MCP client is actively connected.
When enabled, the desktop bridge:
- binds only to
127.0.0.1on port4005by default; - requires the generated bearer token written to
~/.feather/mcp.json; - redacts
appId,apiKey, tokens, passwords, and secrets from exposed MCP resources; - exposes Shader Graph, Particles Playground, Texture Lab, and plugin catalog/live state as local development surfaces;
- keeps Console eval behind the normal Console plugin,
evalEnabled, andapiKeygates.
Use stdio for local AI clients when possible:
Use Streamable HTTP only when the MCP host needs it, and keep the default localhost binding:
See MCP for the complete resource/tool list and client setup examples.
CLI-Managed Debugging¶
Important
The CLI is the preferred workflow for desktop, web, Android, iOS, and packaged desktop builds. You do not need to add require("feather.auto"), call DEBUGGER:update(dt), or keep Feather-specific code in your game.
Use the CLI for local and platform runs:
feather init path/to/my-game
feather run path/to/my-game
feather run path/to/my-game --target web
feather run path/to/my-game --target android
feather run path/to/my-game --target ios
Add vendors for platform targets once per project:
Run doctor as a release gate before packaging:
--production exits with code 1 for release blockers such as insecure connections, weak Console auth, hot reload, debugger/screenshot/disk persistence settings, network exposure with weak auth, or unmanaged embedded Feather runtime.
For CI systems that need a security-only machine-readable report:
The security report includes config posture, plugin trust, package provenance, and network exposure. It redacts sensitive values such as apiKey.
If you use Feather's local release helpers, keep release metadata in feather.build.json and let doctor check the target-specific tools before CI runs the build:
feather build vendor add all --dir path/to/my-game --json
feather build web --dir path/to/my-game --json
feather build android --dir path/to/my-game --release --json
feather build ios --dir path/to/my-game --release --json
feather build windows --dir path/to/my-game --json
feather upload itch web --dir path/to/my-game --dry-run --json
Web builds package a local love.js player; mobile targets use official LÖVE templates; desktop targets use local LÖVE runtime vendors. Mobile release mode is opt-in with --release and produces Android AAB/APK or iOS archive/IPA artifacts. Release builds do not auto-embed Feather's debugger runtime.
For store-oriented mobile releases, Feather can also scaffold and run editable Fastlane lanes:
feather release init --dir path/to/my-game
feather release ios beta --dir path/to/my-game
feather release ios production --dir path/to/my-game
feather release android beta --dir path/to/my-game
feather release android production --dir path/to/my-game
Fastlane is optional. Feather still creates the clean mobile artifact first, then passes explicit FEATHER_* environment variables to the selected lane. Keep secrets such as App Store Connect keys, Google Play service account JSON, Android keystore passwords, and match credentials in your shell or CI environment; feather.build.json should only contain non-secret ids and environment variable names.
Performance¶
Warning
Feather is a development tool, not something you should ship in production builds. Prefer CLI-managed runs and builds so release artifacts stay clean by default.
Release builds¶
feather build android --dir path/to/my-game --release
feather build ios --dir path/to/my-game --release
--release disables automatic debugger embedding for mobile builds. The generated .love used for the release artifact contains the game source, not Feather's injected .feather-main.lua, feather/auto.lua, plugin files, or generated debug config.
Self-cleaning managed files¶
If you used feather init while experimenting, Feather can preview and remove its own generated files:
The remove command only edits generated FEATHER-INIT blocks and removes generated Feather files it can identify. If you want to keep part of the setup:
feather remove path/to/my-game --keep-config
feather remove path/to/my-game --keep-runtime
feather remove path/to/my-game --keep-main
Tip
This is the recommended workflow for most projects because Feather can clean up after itself before production packaging.
Advanced manual integration¶
Manual Lua integration is still available for unusual projects, but it is no longer the recommended path. If you wire Feather by hand, wrap the entire setup in a conditional so the library is never loaded in production:
if Config.IS_DEBUG then
require("feather.auto").setup({ sessionName = "My Game" })
end
function love.update(dt)
if DEBUGGER then DEBUGGER:update(dt) end
end
No Lua code runs and no globals are created in release builds.
Manual exclusion¶
If you manually vendored Feather, excluding it is a single glob:
Manual zip:
makelove — add to makelove.toml:
Important
No Feather code or assets are present in the release build. This also eliminates the Console plugin as an attack surface entirely.
If you used manual mode, also exclude or remove:
feather remove --yes handles these generated files automatically when they are present.
In-game Observability¶
OverlayStats by Oval-Tutu is a great companion for visualizing performance directly in the game window. Feather's performance plugin draws inspiration from it.