Horizon vs Expose
Horizon costs less for a reserved subdomain and needs no PHP. Expose adds custom domains, basic auth, server regions and self-hosting.
Last checked October 2026
npm install -g @hrzn/cliThe short version
Which one fits you
Pick Horizon if…
- You want a reserved subdomain at a lower yearly price than Expose Pro.
- You do not want PHP on your machine. Horizon installs with npm.
- You want free tunnels. Expose Hobby connections have a time limit.
- You want a request log hosted for you, kept for 24 hours in the dashboard.
Pick Expose if…
- You need a custom domain, which Expose offers on Pro.
- You need basic auth on the tunnel.
- You want to choose a server region: Pro has 7.
- You want to self-host the open-source server, or you use Laravel Herd.
Side by side
Horizon and Expose, topic by topic
URLs and domains
| Feature | Horizon | Expose |
|---|---|---|
| Free tunnel URL | Random subdomain | Random URL |
| Reserved subdomain | Paid per slot | Pro and Team |
| Custom domain | No | Yes, on Pro, with a CNAME |
| Server region | No choice | Germany on Hobby, 7 regions on Pro |
Protocols
| Feature | Horizon | Expose |
|---|---|---|
| HTTPS | Yes | Yes, with TLS |
Security and access
| Feature | Horizon | Expose |
|---|---|---|
| Basic auth | No | Yes, with --basicAuth |
| Self-hosting | No | Yes, open-source server under MIT |
Inspection
| Feature | Horizon | Expose |
|---|---|---|
| Request inspection | Dashboard request log, hosted, kept 24 hours | Local dashboard on port 4040 |
| Replay | Yes, while the tunnel is connected | Yes, from the local history |
Setup
| Feature | Horizon | Expose |
|---|---|---|
| Install | npm install -g @hrzn/cli | Needs PHP: composer global require exposedev/expose, or a PHAR |
| Account | Required: hrzn login | Required: expose token <token> |
Pricing
What a stable URL costs
Price
| Feature | Horizon | Expose |
|---|---|---|
| Free tunnels | Free, random subdomain | Hobby $0: random URLs, a time limit per connection, one server in Germany |
| One stable URL | €1 per slot per month, or €10 per slot per year | $79 per user per year (Pro, annual only) |
One stable URL for a year: €10 on Horizon, $79 on Expose.
Expose Team is $229 a year for up to 10 users. Expose prices are in USD, net of tax. Expose prices checked October 2026. The two sets of prices use different currencies and are not converted.
Switching
Switching from Expose
Expose needs PHP and Composer. Horizon needs npm. Replace 3000 with the port of your local server.
composer global require exposedev/exposenpm install -g @hrzn/cliexpose token <token>hrzn loginReserved subdomain on Pro or Teamhrzn tunnel http://localhost:3000 -s my-appexpose --basicAuth="admin:secret"No equivalent: Horizon has no basic authFAQ
Questions about Expose
Is Expose free?
Yes. The Expose Hobby plan costs $0. It gives random URLs on one server in Germany with TLS. Each connection has a time limit, and we did not find how long it is.
How much does a reserved subdomain cost on Expose?
Reserved subdomains need Pro or Team. Pro is $79 per user per year, billed annually only. Team is $229 a year for up to 10 users. Expose prices are in USD, net of tax. Horizon prices are in the table above.
Do I need PHP to use Expose?
Yes. The Expose client is written in PHP. You install it with composer global require exposedev/expose or as a PHAR. Laravel Herd bundles it. Horizon installs with npm install -g @hrzn/cli.
Can I use a custom domain or basic auth with Horizon?
No. Horizon has no custom domains and no basic auth. Expose supports custom domains on Pro with a CNAME, and basic auth with expose --basicAuth.
Where do the tunnels run?
Expose Hobby uses one EU server in Germany, and Pro has 7 server regions. Horizon does not let you choose a region.
Can I self-host?
With Expose, yes. The server is open source under the MIT licence. Horizon is a hosted service and cannot be self-hosted.
Put localhost online.
Install the CLI, sign in and run one command.
npm install -g @hrzn/cli$ hrzn tunnel http://localhost:3000 -s my-app
HORIZON: Tunnel connected
URL https://my-app.hrzn.run (reserved)
Forwarding http://localhost:3000
Request log https://hrzn.run/dashboard/tunnels/my-app
POST 200 /webhooks/stripe
GET 200 /