Skip to main content

Overview

Development mode (connect dev) provides a streamlined workflow for connecting to multiple services defined in a project configuration file.

Project Configuration

Creating a Config File

Initialize a project configuration:
connect dev init
This creates pconnect.yml in your current directory:
# Private Connect project config
# Run: connect dev

services:
  - name: staging-db
    port: 5432
  - name: redis
    port: 6379

Configuration Format

Private Connect supports multiple formats:
services:
  - name: staging-db
    port: 5432
    protocol: tcp
  
  - name: staging-api
    port: 8080
    protocol: http
  
  - name: redis
    port: 6379

hub: https://hub.privateconnect.io

Field Reference

FieldTypeRequiredDescription
namestringYesService name (must match exposed service)
portnumberNoLocal port to bind (auto-selected if omitted)
localPortnumberNoAlias for port
protocolstringNoProtocol hint: tcp, http, https

Hub Configuration

services:
  - name: my-service
    port: 3000

# Override default hub
hub: https://custom-hub.example.com

Starting Dev Mode

Basic Usage

1

Create Config

connect dev init
2

Edit Services

services:
  - name: staging-db
    port: 5432
  - name: staging-redis
    port: 6379
3

Start Dev Mode

connect dev
Output:
🚀 Private Connect Dev Mode

  Config: pconnect.yml
  Hub:    https://hub.privateconnect.io

  Connecting to services...

  [ok] 2 service(s) connected:

    staging-db localhost:5432
    staging-redis localhost:6379

  Set in your .env:
    STAGING_DB_URL=localhost:5432
    STAGING_REDIS_URL=localhost:6379

  Press Ctrl+C to disconnect all services

Custom Config Path

# Use a different config file
connect dev --file ./configs/production.yml

# Use config from parent directory
connect dev --file ../team-services.yml

Config File Discovery

Private Connect searches for config files in this order:
const CONFIG_FILENAMES = [
  'pconnect.yml',
  'pconnect.yaml',
  'pconnect.json',
  '.pconnect.yml',
  '.pconnect.yaml',
  '.pconnect.json',
];
It also searches up to 3 parent directories:
# Current structure:
# /home/user/projects/myapp/src/
# /home/user/projects/myapp/pconnect.yml

cd /home/user/projects/myapp/src
connect dev
# ✓ Finds ../pconnect.yml automatically

Hot Reload

Automatic Service Updates

Dev mode watches for service changes and updates routes automatically:
// From dev.ts - file watching implementation
const routeWatcher = fs.watch(routesDir, (event, filename) => {
  if (filename === 'active-routes.json') {
    if (routeDebounce) clearTimeout(routeDebounce);
    routeDebounce = setTimeout(async () => {
      activeRoutes = loadActiveRoutes();
      routes = buildRouteTable(hubServices, activeRoutes);
    }, 100);
  }
});

What Triggers Hot Reload

# Terminal 1: Dev mode running
connect dev

# Terminal 2: Add new service
connect reach new-service 9000

# Terminal 1: Automatically picks up new route
# ✓ new-service now available at localhost:9000
# Stop a service (Ctrl+C on reach command)
# Routes automatically updated
# Service no longer available
# Refreshes every 10 seconds
const hubRefreshInterval = setInterval(refreshAll, 10000);

# New services exposed by teammates
# Automatically available in dev mode

Manual Reload

Restart dev mode to force a full reload:
# Ctrl+C to stop
# Then restart
connect dev

Port Management

Automatic Port Selection

If the requested port is in use, Private Connect auto-selects an alternative:
# Port 5432 already in use by local PostgreSQL
connect dev
Output:
[ok] 3 service(s) connected:

  staging-db localhost:5433 (was 5432)
  staging-redis localhost:6379
  staging-api localhost:8080
Implementation:
if (!(await isPortAvailable(localPort))) {
  const alternativePort = await findAvailablePort(localPort + 1);
  if (alternativePort) {
    actualPort = alternativePort;
    wasAutoSelected = true;
  } else {
    throw new Error(`Port ${localPort} is in use and no alternatives available`);
  }
}

Fixed Port Assignment

services:
  # These ports MUST be available
  - name: postgres
    port: 5432
  
  - name: mysql  
    port: 3306
If ports are in use, dev mode will fail with a clear error:
[!] 1 service(s) failed:

  postgres: Port 5432 is in use and no alternatives available

Dynamic Port Configuration

services:
  # Let Private Connect choose
  - name: staging-db
    # port omitted - will use service's targetPort from hub
  
  - name: staging-api
    # port: 0 means "auto-select any available port"
    port: 0

Shell Integration

Environment Variables

Dev mode suggests environment variables:
🚀 Private Connect Dev Mode

  [ok] 3 service(s) connected

  Set in your .env:
    STAGING_DB_URL=localhost:5432
    STAGING_REDIS_URL=localhost:6379
    STAGING_API_URL=localhost:8080
Variable naming convention:
// Service name: staging-db
const envName = serviceName
  .toUpperCase()           // STAGING-DB
  .replace(/-/g, '_');     // STAGING_DB
  
// Result: STAGING_DB_URL=localhost:5432

Shell State File

Private Connect maintains state for shell prompt integration:
// ~/.connect/shell-state.json
{
  "services": [
    { "name": "staging-db", "port": 5432 },
    { "name": "redis", "port": 6379 }
  ],
  "workingDir": "/home/user/projects/myapp",
  "updatedAt": "2026-03-02T10:30:00Z"
}

Shell Prompt Indicator

Add to your shell prompt to show active services:
# Add to ~/.bashrc or ~/.zshrc
function pconnect_prompt() {
  local state_file="$HOME/.connect/shell-state.json"
  if [ -f "$state_file" ]; then
    local count=$(jq -r '.services | length' "$state_file" 2>/dev/null)
    if [ "$count" -gt 0 ]; then
      echo "[↔ $count]"
    fi
  fi
}

# Add to PS1
PS1="$(pconnect_prompt) $PS1"
Result:
[↔ 3] user@host:~/project$ 

Development Workflows

Team Synchronization

# Commit to version control
# pconnect.yml
services:
  - name: shared-db
    port: 5432
  - name: shared-cache
    port: 6379
  - name: staging-api
    port: 8080
Team members can then:
git clone <repo>
cd <repo>
connect dev  # Automatically connects to all services

Multi-Environment Setup

services:
  - name: staging-db
    port: 5432
  - name: staging-api
    port: 8080

hub: https://staging-hub.example.com
Usage:
# Development
connect dev --file pconnect.staging.yml

# Production debugging
connect dev --file pconnect.production.yml

Monorepo Support

# Root pconnect.yml for shared services
# packages/api/pconnect.yml for API-specific services
# packages/frontend/pconnect.yml for frontend-specific services

# In any package:
cd packages/api
connect dev  # Uses local pconnect.yml

cd packages/frontend  
connect dev  # Uses different pconnect.yml

cd ../..  # Root
connect dev  # Uses root pconnect.yml

Advanced Configuration

Service Validation

// Dev mode validates services exist on hub
const availableService = availableServices.find(
  s => s.name.toLowerCase() === service.name.toLowerCase()
);

if (!availableService) {
  results.push({
    name: service.name,
    success: false,
    error: 'Service not found on hub',
  });
  continue;
}

if (!availableService.tunnelPort) {
  results.push({
    name: service.name,
    success: false,
    error: 'Service has no active tunnel',
  });
}

Tunnel Creation

// Creates bidirectional TCP tunnel
const server = net.createServer((clientSocket) => {
  const proxySocket = net.createConnection({
    host: hubHost,
    port: tunnelPort,
  }, () => {
    clientSocket.pipe(proxySocket);
    proxySocket.pipe(clientSocket);
  });

  proxySocket.on('error', () => clientSocket.destroy());
  clientSocket.on('error', () => proxySocket.destroy());
});

Graceful Cleanup

const cleanup = () => {
  console.log('\n👋 Disconnecting services...');
  tunnels.forEach(t => t.server.close());
  clearShellState();
  process.exit(0);
};

process.on('SIGINT', cleanup);
process.on('SIGTERM', cleanup);

Best Practices

Version Control

Commit pconnect.yml to share team configuration:
git add pconnect.yml
git commit -m "Add Private Connect config"

Environment Variables

Use suggested env vars in your .env:
DATABASE_URL=postgresql://localhost:5432
REDIS_URL=redis://localhost:6379

Port Conflicts

Let auto-selection handle conflicts:
# Omit port for automatic selection
- name: staging-db
  # port not specified

Multiple Environments

Use separate configs per environment:
pconnect.dev.yml
pconnect.staging.yml
pconnect.prod.yml

Troubleshooting

Config Not Found

[!] No project config found.

  Create a pconnect.yml file:

    services:
      - name: staging-db
        port: 5432
Solution:
connect dev init

Service Not Available

[!] 1 service(s) failed:

  staging-db: Service not found on hub
Check if service is exposed:
connect whoami
# View all exposed services

Port Already in Use

[ok] 1 service(s) connected:

  staging-db localhost:5433 (was 5432)
This is expected behavior. To use the exact port:
# Stop conflicting service
lsof -ti:5432 | xargs kill

# Restart dev mode
connect dev

Build docs developers (and LLMs) love