The Route Tax

You’ve adopted vanity URLs for your Go modules. Clean import paths, platform-independent, looking good:

import "go.mycorp.com/auth"
import "go.mycorp.com/config"
import "go.mycorp.com/logger"

Then your team grows. New services get created every sprint. And every single one needs its own gvu add command:

gvu add go.mycorp.com/auth https://github.com/mycorp/auth.git
gvu add go.mycorp.com/config https://github.com/mycorp/config.git
gvu add go.mycorp.com/logger https://github.com/mycorp/logger.git
gvu add go.mycorp.com/cache https://github.com/mycorp/cache.git
gvu add go.mycorp.com/queue https://github.com/mycorp/queue.git
# ... 45 more

Fifty repos. Fifty routes. Every new repo means a pull request to update the routing config. Someone forgets? The new service’s go get fails and the team is blocked.

This is the route tax — the overhead of maintaining vanity URL mappings that should just be automatic.


One Rule, Every Repo

Wildcard routing eliminates the route tax. Instead of adding each repo individually, you write one rule that covers all repos under a path prefix:

gvu add 'go.mycorp.com/*' 'https://github.com/mycorp/*.git'

That’s it. One line. Now every repo in your mycorp GitHub org is automatically importable:

import "go.mycorp.com/auth"       // → github.com/mycorp/auth
import "go.mycorp.com/config"     // → github.com/mycorp/config
import "go.mycorp.com/logger"     // → github.com/mycorp/logger
import "go.mycorp.com/newthing"   // → github.com/mycorp/newthing (works immediately!)

Create a new repo on GitHub? It’s instantly go get-able under your vanity domain. No config update. No pull request. No waiting.

This is Repo Wildcard (W1) — the * in the vanity path matches any single path segment, and the * in the repo URL gets replaced with the matched name.


Monorepo? Subdir Wildcard

What if your modules live in a monorepo instead of separate repos?

monorepo/
├── go/
│   ├── auth/go.mod
│   ├── config/go.mod
│   ├── logger/go.mod
│   ├── cache/go.mod
│   └── ... 20 more

You don’t need a repo wildcard. You need a Subdir Wildcard (W2):

gvu add go.mycorp.com/libs https://github.com/mycorp/monorepo.git '--subdir=*'

Every Go module under any subdirectory of the monorepo is now automatically importable:

import "go.mycorp.com/libs/auth"     // → monorepo, subdir go/auth
import "go.mycorp.com/libs/config"   // → monorepo, subdir go/config
import "go.mycorp.com/libs/cache"    // → monorepo, subdir go/cache

Add a new module to the monorepo? Automatically importable — no route changes needed.

Note: Subdir wildcard requires Go 1.25+ in each module’s go.mod. See our monorepo tutorial for the full setup.


Real-World Scenarios

Scenario 1: Multi-team organization

Your company has three teams, each with their own GitHub org:

# Platform team — 15 repos
gvu add 'go.mycorp.com/platform/*' 'https://github.com/mycorp-platform/*.git'

# Data team — 12 repos
gvu add 'go.mycorp.com/data/*' 'https://github.com/mycorp-data/*.git'

# Infra team — 8 repos in a monorepo
gvu add go.mycorp.com/infra https://github.com/mycorp-infra/monorepo.git '--subdir=*'

Three rules. Thirty-five modules. Zero maintenance.

Scenario 2: Override specific repos

Sometimes a repo doesn’t follow the convention. Maybe it’s in a different org, or it’s a fork. Use an exact route to override:

# Wildcard covers most repos
gvu add 'go.mycorp.com/*' 'https://github.com/mycorp/*.git'

# But auth was moved to a different org
gvu add go.mycorp.com/auth https://github.com/security-team/auth.git

# And logger is a maintained fork
gvu add go.mycorp.com/logger https://github.com/upstream/logger.git

gvu resolves conflicts using priority rules:

PriorityRule typeWhen it matches
1 (highest)Exact routeSpecific override for one repo
2Subdir wildcard (W2)Monorepo sub-packages
3 (lowest)Repo wildcard (W1)Catch-all for the org

Exact routes always win over wildcards. This lets you have a broad default with surgical exceptions.

Scenario 3: Gradual adoption

Not ready to go all-in on wildcards? Start with exact routes for your most-used modules, then add a wildcard when the route count gets annoying:

# Week 1: Just a few modules
gvu add go.mycorp.com/auth https://github.com/mycorp/auth.git
gvu add go.mycorp.com/config https://github.com/mycorp/config.git

# Week 5: Too many to manage individually
gvu add 'go.mycorp.com/*' 'https://github.com/mycorp/*.git'
# The exact routes still work — they have higher priority

How It Works Under the Hood

When a developer runs go get go.mycorp.com/auth, the Go toolchain sends a request to https://go.mycorp.com/auth?go-get=1. gvu’s server:

  1. Checks exact routes first — is there a route for go.mycorp.com/auth?
  2. Checks subdir wildcards (W2) — does any W2 rule’s prefix match?
  3. Checks repo wildcards (W1) — does any W1 rule’s pattern match?

When a wildcard matches, the server generates the go-import meta tag on the fly:

<!-- W1 match: go.mycorp.com/auth → github.com/mycorp/auth -->
<meta name="go-import" content="go.mycorp.com/auth git https://github.com/mycorp/auth">

<!-- W2 match: go.mycorp.com/libs/auth → github.com/mycorp/mono subdir go/auth -->
<meta name="go-import" content="go.mycorp.com/libs/auth git https://github.com/mycorp/mono go/auth">

No static HTML files. No Nginx config. The meta tags are generated dynamically from your wildcard rules.


Prerequisites

Wildcard routing is a Pro feature. Here’s what you need:

RequirementDetails
Pro accountRun gvu subscribe — 50 routes, custom domains, wildcards
Custom domaingo.mycorp.com with DNS CNAME pointing to gvu
gomod.io not supportedWildcards require your own domain

The custom domain requirement makes sense — a wildcard under gomod.io would let anyone claim any path under that domain, which is a security risk.

Setting up the custom domain

# 1. Add a CNAME record
go.mycorp.com  CNAME  gomodvanityurls.com

# 2. Verify with gvu
gvu domain add go.mycorp.com
gvu domain verify go.mycorp.com

# 3. Create your wildcard route
gvu add 'go.mycorp.com/*' 'https://github.com/mycorp/*.git'

HTTPS certificates are provisioned automatically — no cert management needed.


Limits and Gotchas

A few things to keep in mind:

  • One * per rule — you can’t do go.mycorp.com/*/* (two wildcards in the path)
  • W1 and W2 are mutually exclusive per route — a single route uses either repo wildcard or subdir wildcard, not both
  • Each wildcard counts as 1 route against your Pro quota (50 total)
  • Shell quoting matters — always wrap arguments containing * in single quotes:
# ✅ Correct
gvu add 'go.mycorp.com/*' 'https://github.com/mycorp/*.git'

# ❌ Wrong — shell expands the glob
gvu add go.mycorp.com/* https://github.com/mycorp/*.git

Before and After

AspectIndividual routesWildcard routing
SetupOne command per moduleOne command per org/monorepo
New repoMust add route firstWorks immediately
Route countN repos = N routesN orgs = N rules
MaintenanceUpdate on every new serviceSet and forget
OverrideN/AExact routes take priority

Summary

If you have more than 5 Go modules, wildcard routing pays for itself immediately:

# Multi-repo org: one rule covers everything
gvu add 'go.mycorp.com/*' 'https://github.com/mycorp/*.git'

# Monorepo: one rule covers all sub-packages
gvu add go.mycorp.com/libs https://github.com/mycorp/mono.git '--subdir=*'

# Mix and match with exact overrides
gvu add go.mycorp.com/special https://github.com/other/special.git

One rule per org. One rule per monorepo. Exact routes for exceptions. That’s the entire routing config for a 50-module organization.

Upgrade to Pro and set up wildcard routing in under 5 minutes.