Consul’s service discovery isn’t just for services running inside your Consul cluster; you can register external services, making them discoverable by your internal applications as if they were managed by Consul itself.

Let’s watch a service registration in action. Imagine we have an external PostgreSQL database at db.example.com:5432 that our internal microservices need to connect to. We’ll register it with Consul using the consul services register command.

consul services register \
  -name=external-postgres \
  -id=external-postgres-main \
  -port=5432 \
  -address=db.example.com \
  -tags='database,postgres,production' \
  -meta='env=production,owner=db-team'

Here’s what’s happening:

  • -name=external-postgres: This is the logical name your internal services will use to find this PostgreSQL instance.
  • -id=external-postgres-main: A unique identifier for this specific registration. Useful if you have multiple instances of the "same" external service.
  • -port=5432: The port the external service is listening on.
  • -address=db.example.com: The hostname or IP address of the external service. This is crucial for Consul to know where to direct requests.
  • -tags='database,postgres,production': These are labels that can be used for filtering and routing. Your services can query for all services tagged database or production.
  • -meta='env=production,owner=db-team': Arbitrary key-value pairs for additional metadata. This can be used for configuration, ownership, or any other context.

Once registered, any service querying Consul for external-postgres will receive the address db.example.com:5432.

This capability is fundamental for a unified discovery plane. It allows you to gradually migrate services to a Consul-managed environment or integrate with legacy systems without requiring those systems to be Consul-aware. You can add external databases, message queues, third-party APIs, or even on-premises services to your Consul catalog, presenting a single pane of glass for service lookup.

The core mechanism relies on Consul’s agent. When you run consul services register, you’re essentially telling the Consul agent on your local machine (or the agent where you execute the command) to add this service definition to its local catalog. This information is then gossiped throughout the Consul cluster. Importantly, for external services, Consul doesn’t manage their lifecycle (it won’t start, stop, or health check them by default). It simply knows about them and their network location.

To make this truly useful, you’ll often combine external service registration with Consul’s health checking and Intentions. For example, you might register a simple HTTP check for an external API:

consul services register \
  -name=external-api \
  -id=external-api-v1 \
  -address=api.thirdparty.com \
  -port=443 \
  -tags=api,external \
  -check='http:https://api.thirdparty.com/health?token=YOUR_SECRET_TOKEN interval=30s timeout=5s'

This registers the API and then adds a health check. If the /health endpoint returns a non-2xx status code, Consul will mark external-api-v1 as unhealthy, and clients querying for external-api will stop receiving its address until it becomes healthy again. This is how you achieve resilience and avoid sending traffic to unavailable external dependencies.

The consul services register command is a powerful tool, but it’s also easy to misconfigure the address or port if the external service changes. This requires a process for updating these registrations, perhaps through a CI/CD pipeline that re-registers the service with updated parameters. Without this, your internal services could be directed to the wrong place or fail to connect.

The most surprising truth is that Consul’s own internal service registry is just a specific case of this external registration mechanism; services running on Consul agent nodes are registered with their local IP and port, but the underlying API and protocol for registering any service, internal or external, is identical. This unified approach simplifies how you think about your entire application topology.

For more advanced scenarios, you can use Consul Connect to secure communication to these external services, even if they don’t natively support mTLS, by proxying traffic through Consul proxies.

The next logical step is to explore how to automatically manage these registrations, especially when dealing with dynamic external environments.

Want structured learning?

Take the full Consul course →