localdeck
v1.9.2
Published
Stable ports, shareable HTTPS links and request logs for your local dev servers
Maintainers
Readme
LocalDeck
One place to run, inspect, and share your local development services.
LocalDeck runs the commands your project already uses, gives web services stable local addresses, and brings their controls and logs into a browser dashboard. Use it for a single app or a monorepo with frontends, APIs, and database dependencies. Maintained by jus-ta-dev.
Install
Requires Node.js 20 or newer. The npm package includes the CLI, background daemon, and dashboard; Bun is only needed to develop LocalDeck.
npm install -g localdeck
localdeck --versionTo update later, run localdeck --update (LocalDeck 1.0.3 or newer). It installs the latest release into the same global npm installation and restarts the daemon. Restarting stops managed services and public shares, so start them again afterward. Older versions can upgrade with npm install -g localdeck@latest using their existing npm prefix. See updating (included as docs/commands.md) for supported installation layouts.
Quick start
In your application's directory:
localdeck init --dry-run # Preview services detected from package.json
localdeck init # Save the .localdeck configuration
localdeck doctor # Check configuration and required tools
localdeck up # Start the project and its dependenciesIn another terminal:
localdeck open # Open the dashboardThe dashboard is served at http://localhost:7777 by default. It remembers projects registered through the CLI. You can start and stop a whole project or individual services, open local and shared links, and inspect logs and requests on service pages or in a resizable panel.
To run part of a project, name a service (localdeck web) or a tag (localdeck up frontend); LocalDeck also starts its prerequisites. localdeck up runs in the foreground: Ctrl-C stops the services it owns. Services started from the dashboard continue in the background until you stop them or shut down the daemon.
What you get
- Stable addresses: keep a consistent local port even when the development server chooses another upstream port.
- Project and service pages: start or stop a whole project in dependency order, inspect each service's Logs, Requests, and Config tabs, and see when a running service needs a restart to apply changed settings.
- Automatic recovery: a service that exits unexpectedly is restarted up to three times, three seconds apart.
- Databases and workers: run PostgreSQL, Redis, and Docker Compose services with readiness checks, and background workers that never open a port.
- Stackable profiles: change a service's command, working directory, environment, or secrets for setups such as staging and debugging while keeping its name and stable address.
- Clean URLs: optional addresses such as
http://platform.web.localhost, with a project nickname and port-80 forwarding enabled. - Project secrets: store values outside your project and pass them to services as environment variables. Manage them in the project's Secrets tab.
- Logs and requests panel: watch multiple services from the bottom bar or with ⌘J / Ctrl+J, filter retained output, and choose a log display limit from 100 to 5,000 lines.
- Command palette: press ⌘K / Ctrl+K or choose Search in the sidebar to find projects, open apps and logs, and start, stop, or restart services.
- HTTPS sharing: create temporary Cloudflare links protected by a generated password by default, with pending status and shared-request logs.
- Coding-agent access: an MCP server for service inspection and controls, logs and requests, profiles, sharing, and recorded GET/HEAD replay.
- Activity and comparisons: inspect a unified incident timeline in a scrollable panel with live updates, and mark a baseline to see what changed.
- Worktree environments: discover existing Git worktrees and switch between separately registered service environments.
- Request reproduction: preview sanitized cURL exports and save explicit GET/HEAD status checks.
Configure your services
Run localdeck init in your application's directory. It detects your package scripts and writes .localdeck using a commands array. You can then edit the generated commands, or set a project nickname and edit ports, readiness, and startup order in the project's Settings tab.
For example, a project with dev:api and dev:web scripts can use:
{
"nickname": "platform",
"commands": [
{ "name": "api", "run": "npm run dev:api" },
{ "name": "web", "run": "npm run dev:web", "after": "api" }
]
}Use script names that exist in your project. Here, after is an optional customization: it starts the API first and waits for its default TCP readiness check before starting web. Add an HTTP ready check only if your app exposes that endpoint. Add "tag": "frontend" (a string or an array) to start a group with localdeck up frontend.
Commands can require locally saved secrets with "secrets": ["SECRET_KEY"]. Only names go in .localdeck; set values from Project → Secrets. Values are stored in a plaintext file outside the project, not encrypted. Changes apply on the next service start. See configuration (included as docs/configuration.md) for details.
For a non-JavaScript service:
localdeck init --name web --command 'python3 -m http.server {port}'LocalDeck supplies PORT and expands {port} to the application's upstream port. It can also detect listening ports on macOS, Linux, and Windows. Configure upstream explicitly when detection is unavailable. The optional port field is the stable proxy port, not the port your development server should bind.
For scripts such as wrangler dev --port ${API_PORT:-8787}, LocalDeck also supplies the assigned port through API_PORT, without editing your project. It follows individual npm, pnpm, Yarn and Bun scripts, including npm workspace selectors and package directory options. Explicit service env settings and secrets take precedence over inferred variables. Complex shell commands and hardcoded ports continue to use normal socket detection.
See configuration (included as docs/configuration.md) for working directories, profiles, environment references, database services, background workers, and advanced readiness checks.
Switch profiles
Define profiles in .localdeck to change how existing services run. For example, a staging profile can give web a different API URL without changing its name, dependencies, or stable port:
{
"commands": [{ "name": "web", "run": "npm run dev" }],
"profiles": {
"staging": {
"services": { "web": { "env": { "API_URL": "https://api.staging.example.com" } } }
}
}
}Run localdeck profile on staging or use the Profiles menu on the project page. You can turn on several profiles; they apply in file order, with the later profile winning when settings overlap. The selection is saved only on your computer. Switching profiles does not start or restart services, so restart a running service to apply its new settings. Open the service's Config tab to see the resolved command, directory, environment, and secret names. See profiles (included as docs/configuration.md) for the available overrides.
Inspect requests
Open a service's Requests tab, or use the bottom Requests panel to watch several services. Expand a row to inspect headers, cookies, the request body, and the response. Successful assets and development modules are hidden by default. Service pages also have Logs and Config tabs.
Capture works only through LocalDeck's service URLs. A frontend calling Wrangler directly at http://localhost:8787, or through a Worker service binding, bypasses the proxy. Set your app's API base URL to the API service's LocalDeck URL to capture that traffic.
Responses load on demand from a 64 MiB shared cache. Older bodies are evicted as it fills, and the cache resets with the daemon. Saved history retains 16 KiB previews; the inspector identifies expired bodies and incomplete transfers.
Everyday commands
| Command | Purpose |
| --- | --- |
| localdeck commands | List the configured services and remember the project without starting them. |
| localdeck web | Start the configured web service and its prerequisites. |
| localdeck up [tag\|name...] | Start every configured service, or only the tagged or named ones, in one terminal. |
| localdeck run api -- node server.js | Run a one-off command with a stable port, without a configuration file. |
| localdeck profile | List the project's profiles and which are on. |
| localdeck profile on staging | Select the staging overrides for the next service start or restart. |
| localdeck profile off staging / clear | Turn off one profile, or all of them, without stopping running services. |
| localdeck ps | List services with their status, ports, request counts, and share links. |
| localdeck port web | Print a service's stable port, for scripts. |
| localdeck logs web -f | Follow a service's output. |
| localdeck requests web | Inspect recent proxied requests. |
| localdeck open / localdeck open web | Open the dashboard, or a service's local URL. |
| localdeck stop web | Stop a service and its share. |
| localdeck share web | Create a share with a generated password. |
| localdeck unshare web | Close the share while keeping the service running. |
| localdeck doctor | Check the configuration and required tools without starting anything. |
| localdeck daemon status\|start\|stop | Inspect, start, or stop the background daemon. |
| localdeck --update | Update the global npm installation and restart the daemon. |
| localdeck --h / localdeck --v | Show help / version. |
When projects have the same service name, use project/service or the exact key shown by localdeck ps. See the full command reference (included as docs/commands.md).
Share over HTTPS
Sharing requires cloudflared, installed separately and available on PATH. Local services and Clean URLs do not require it. Follow Cloudflare's installation instructions, then check:
cloudflared --version
localdeck share webThe CLI generates a password by default. Use --password <password> to choose one, or --public for an unprotected link. In the dashboard, choose Share… from the service's options menu. Leaving the password blank generates one; select Public link explicitly to create an unprotected share.
The generated URL appears beside a spinner while LocalDeck checks connectivity. After one minute, the dashboard suggests opening the link yourself; a request reaching the public tunnel also confirms connectivity. Startup ends after two minutes if the link still cannot be verified. Pending and failed states survive a dashboard refresh. Protected links have a masked password with Show/Hide.
Quick Tunnel URLs are temporary and may have DNS delays. They stop when the service or daemon stops, and recreating a share changes its address. Cloudflare does not guarantee Quick Tunnel uptime. Named tunnels and custom public domains are not configured by LocalDeck v1.
Clean URLs and networking
Enable Clean URLs in Settings, or use the notice at the bottom of the sidebar. LocalDeck verifies forwarding before removing the port from links. Setup may request administrator approval on macOS or Windows. If forwarding is unavailable, the original port-number URLs remain usable.
CORS still belongs to your application. http://localhost:3001, http://platform.web.localhost, and a public HTTPS tunnel URL are different browser origins. Add the frontend origin you actually visit to your API's allowlist. LocalDeck does not rewrite CORS policies or application API URLs.
Windows process discovery and an administrator forwarder are implemented. Windows UAC installation, removal, and reboot persistence still need manual validation on Windows; see platform details (included as docs/dashboard.md).
Connect a coding agent
Add LocalDeck to an MCP client's server configuration:
{
"mcpServers": {
"localdeck": {
"command": "localdeck",
"args": ["mcp"]
}
}
}Run localdeck commands in your project folder first so the daemon remembers it. Agents can then list services, read logs and requests, start, stop, and restart services, switch profiles, and create shares. Connecting starts no services. Use localdeck mcp --project <id> to restrict access to one remembered project. See MCP setup and tools (included as docs/mcp.md).
Quarry
Quarry is a project in development and is not available to the public yet.
Troubleshooting
Port already in use: check
localdeck psand the service logs. LocalDeck does not terminate unrelated processes. For a strict-port development server, use its assignedPORTor configure the correctupstream.Daemon running but CLI cannot find it after sudo: run
sudo localdeck daemon stoponce, thenlocaldeck daemon startas your normal user. Keep the daemon state private. Use sudo only for a global npm installation when required, not for LocalDeck runtime commands.Sharing fails: check
cloudflared --version, network connectivity, and the sharing error. A local app can work while Cloudflare DNS is unavailable.A project says LocalDeck can't read
.localdeck(permission denied): a long-running daemon can lose access to a file that a fresh process can read, notably on macOS. Restart the daemon as shown below.Changes or upgrades do not take effect: the daemon keeps the code it loaded at startup. Restart it, then start your services again:
localdeck daemon stop localdeck daemon startStopping the daemon ends its running services and shares.
Documentation
- Configuration (included as
docs/configuration.md) - CLI reference (included as
docs/commands.md) - Dashboard and platform support (included as
docs/dashboard.md) - MCP integration (included as
docs/mcp.md) - Changelog (included as
CHANGELOG.md)
License
Free for personal and commercial use, including building and selling your own products. You may not sell LocalDeck, charge for access to it, or claim it as your own product. Modification and redistribution require permission under the custom proprietary license (included as LICENSE). Bundled dependencies retain their own licenses; the package includes THIRD_PARTY_NOTICES.md.
