Skip to main content
ngrok exposes ports to the internet. Private Connect shares services with your team.

The core difference

ngrok creates public URLs for local services. Great for:
  • Showing a client your WIP
  • Testing webhooks locally
  • Quick demos
Private Connect creates named, private services shared across your team. Great for:
  • Team development environments
  • Cross-environment access (staging, prod, home lab)
  • Persistent service discovery
ngrokPrivate Connect
ModelLocal → public URLNamed services → team access
SharingSend a URLconnect clone alice
Access controlURL-based (anyone with link)Team-based (workspace members)
PersistenceURL changes on restart (free tier)Service names are permanent
DirectionOne-way (expose only)Bidirectional (expose + reach)

Side-by-side examples

Sharing a dev server

ngrok:
# You run this
ngrok http 3000
# → https://a1b2c3d4.ngrok.io

# Then you message your teammate:
# "Hey, check out https://a1b2c3d4.ngrok.io"

# Tomorrow, you restart ngrok:
# → https://e5f6g7h8.ngrok.io  (different URL)
# "Hey, new URL: https://e5f6g7h8.ngrok.io"
Private Connect:
# You run this once
connect expose localhost:3000 --name my-api

# Teammate runs this once
connect clone you

# Now they have access. Forever. No URLs to share.
connect reach my-api
# → localhost:3000 on their machine

Accessing a remote database

ngrok:
# ngrok doesn't really solve this
# You'd need to expose the DB publicly (security risk)
# Or set up SSH tunnels manually
Private Connect:
# On the server with the database
connect expose localhost:5432 --name staging-db

# From your laptop (anywhere)
connect reach staging-db
# → localhost:5432 — connected to staging DB
Private Connect is bidirectional. You can expose services and reach remote services.

Team onboarding

ngrok:
New teammate: "How do I access the dev services?"
You: "I'll send you the ngrok URLs... wait, let me restart them first"
You: "OK here's the API: https://abc.ngrok.io, DB: https://def.ngrok.io..."
You: "Oh those expired, here are new ones..."
Private Connect:
New teammate: "How do I access the dev services?"
You: "Run: connect clone alice"
Teammate: "Done. I see staging-db, dev-api, redis-cache..."

Key differences explained

Public vs Private

ngrok creates public URLs. Anyone with the link can access. Private Connect keeps services private. Only workspace members can access. No public URLs, no link sharing.

URLs vs Names

ngrok gives you random URLs: https://a1b2c3d4.ngrok.io Private Connect gives you permanent names: staging-db, prod-api, dev-server Your code can use localhost:5432 and connect reach staging-db makes it work—no URL changes, no config updates.

Solo vs Team

ngrok is designed for solo developers exposing local services. Private Connect is designed for teams sharing environments:
  • connect clone alice — get all of Alice’s exposed services
  • connect share — generate invite links for teammates
  • Workspace-level access control

Auto-reconnect

ngrok requires you to restart the process if the connection drops (free tier). Private Connect tunnels automatically reconnect if the connection drops, up to 10 retries with exponential backoff. No manual restart needed.

One-way vs Bidirectional

ngrok only exposes (local → internet). Private Connect does both:
  • connect expose — make a local service available
  • connect reach — access a remote service locally
This means you can access services running on remote VMs, Kubernetes clusters, or teammates’ machines.

When to use which

Use casengrokPrivate Connect
Quick webhook testing
Demo to external client
Share dev environment with team
Access remote services from laptop
Kubernetes service access from outside cluster
Persistent service names
Cross-environment access (staging + prod)
Team collaboration built-in

Migrating from ngrok

If you’re using ngrok for team collaboration, here’s how to switch:
1

Before: ngrok workflow

# Developer 1
ngrok http 3000
# Share URL in Slack...

# Developer 2
curl https://abc123.ngrok.io/api/health
2

After: Private Connect workflow

# Developer 1 (once)
connect expose localhost:3000 --name my-api

# Developer 2 (once)
connect clone developer1
connect reach my-api
curl localhost:3000/api/health

Benefits of migration:

  • No more URL sharing
  • Service names don’t change
  • Works across all environments
  • Teammates discover services automatically

Quick tunnels (no signup)

Private Connect also handles the quick, no-signup use cases:
# Webhook testing with named subdomain
npx private-connect stripe 3000
# → https://stripe-a1b2.privateconnect.co (readable URL, 2hr expiry)

# Quick demo
npx private-connect myapp 3000
# → https://myapp-f3d9.privateconnect.co

# Anonymous tunnel
npx private-connect tunnel 3000
# → https://abc12345.privateconnect.co
Features: color-coded request log, live stats, auto-reconnect, web inspector.

Still use ngrok for…

  • Custom domains on free tier: ngrok supports this, Private Connect quick tunnels are random or slug-prefixed
Private Connect covers team collaboration, cross-environment access, and quick public tunnels (webhooks, demos).

Getting started

1

Install Private Connect

curl -fsSL https://privateconnect.co/install.sh | bash
2

Expose a service

connect expose localhost:3000 --name my-api
3

Teammate clones your setup

connect clone you
4

They can now reach your services

connect reach my-api

Summary

ngrokPrivate Connect
Best forQuick public URLsTeam service sharing
Access modelAnyone with URLWorkspace members only
Service namesRandom URLsPermanent names
DirectionExpose onlyExpose + Reach
Team featuresNoneClone, share, workspaces
PersistenceURLs change (free tier)Names are permanent
ReconnectManual restartAutomatic (with backoff)
Use ngrok when you need a public URL fast. Use Private Connect when you need team collaboration and cross-environment service access.

Build docs developers (and LLMs) love