Routes
server.RoutesConfig links public patterns to internal destinations before solving Pages, Actions or static files.
module routes
import "github.com/gox-lang/gox/server"
var Config = server.RoutesConfig{
Routes: map[string]string{
"/": "/index",
"/about": "/company/about",
"/users/:id": "/users/profile",
"/blog/:?category": "/blog/index",
"/(photos|images)/*": "/public/assets",
"/files/report-*.pdf": "/downloads/report",
},
} The key to the map is the public pattern and the value is the internal destination. An empty map does not add custom routes.
Patterns
The patterns are divided into segments by /. GOX accepts exact routes, parameters, optional segments, alternatives and wildcard in the final segment.
The initial bar can be omitted and the final bars are removed during normalization. about, /about and /about/ they represent the same pattern.
Exact route
"/about": "/company/about", It just matches /about.
Parameter
"/users/:id": "/users/profile", Coincide with /users/42 and exposes id by ctx.Request.Route.Params.
id, exists := ctx.Request.Route.Params.Get("id") Optional segment
"/blog/:?category": "/blog/index", Coincide with /blog and /blog/gox.
The recommended form is :?category. The form above :category? It is preserved by compatibility. After the first optional parameter, a literal segment, a mandatory parameter or a covert cannot appear.
Alternatives
"/(photos|images)/*": "/public/assets", It matches so much with /photos/* as with /images/*For example:
/photos/avatar.webp
/images/gallery/summer/photo.jpg In both cases, the destination is exactly /public/assets. GOX does not add to the destination the content consumed by *:
| Original URL | Pattern | Internal destination |
|---|---|---|
/photos/avatar.webp | /photos/* | /public/assets |
/images/gallery/photo.jpg | /images/* | /public/assets |
The wildcard is used to select the route, not to dynamically build the destination. If the destination is a Page or Action, you can check the original URL by using ctx.Request.Route.Original(). Wildcards do not create a parameter in ctx.Request.Route.Params.
The alternatives are separated with | within parentheses. They can be part of a segment and combined with prefixes or suffixes:
"/download/file-(small|large).(jpg|webp)": "/downloads/image", This pattern expands into the four possible combinations. Empty alternatives and nested parentheses are not valid.
Trailing wildcard
"/assets/*": "/public/assets", Coincide with /assets, /assets/app.js and any further depth. The covert can only appear in the final segment.
The pure wildbox accepts zero or more segments. /assets/* also coincides with /assets.
Partial wildcard
"/files/report-*.pdf": "/downloads/report", It matches names like /files/report-2026.pdf. A partial covert must appear in the last segment and requires content that can be checked against its prefix or suffix.
The covert consumes the rest of the route, even when it contains more than one segment. /files/*.pdf It matches /files/report.pdf and /files/2026/reports/report.pdf.
Files and extensions
An extension can be declared as a literal part of a route:
"/favicon.ico": "/assets/favicon.ico", You can also restrict a parameter or a wildcard:
"/documents/:name.pdf": "/documents/show",
"/documents/*.pdf": "/documents/archive", /documents/:name.pdf matches a single segment that ends in .pdf. The parameter retains the full segment, including the extension:
name, exists := ctx.Request.Route.Params.Get("name")
// name == "guide.pdf" /documents/*.pdf accepts any depth, but requires that the rest of the route end in .pdf.
To accept files with any extension or without extension, use a non-suffix wildbox:
"/documents/*": "/documents/archive", This pattern matches /documents, /documents/readme, /documents/photo.jpg and /documents/2026/report.pdf.
| Pattern | Coincide with | It doesn't match |
|---|---|---|
/files/readme | /files/readme | /files/readme.txt |
/files/:name | /files/readme, /files/readme.txt | /files/archive/readme |
/files/:name.txt | /files/readme.txt | /files/readme, /files/archive/readme.txt |
/files/* | /files, /files/readme, /files/a/readme.txt | — |
/files/*.txt | /files/readme.txt, /files/a/readme.txt | /files/readme, /files/photo.jpg |
Rules and validation
- The parameters start with
:and its name supports letters, numbers,_and-. - The parameters match exactly one segment.
- The parameters with extension retain the extension in the captured value.
*can be used only once and only in the final segment.- A partial wildcard may have a prefix, a suffix or both.
- The optional segments must occupy the final part of the pattern.
- The alternatives cannot be empty or contain nested parentheses.
Resolution
GOX first tests the exact coincidences and then the dynamic rules compiled. The destination changes the internal resolution, but retains the original URL.
original := ctx.Request.Route.Original()
pattern := ctx.Request.Route.Pattern()
target := ctx.Request.Route.Target() Pattern() returns the expanded pattern that produced the coincidence. For example, a request to /photos/avatar.webp configured by /(photos|images)/* produce /photos/*.
Target() literally returns the configured destination. The values captured by parameters and wildcard are not interpolated within the destination.
See Request Route to know the parameters and metadata available during an request.
The same compiled grammar is used in RateLimitRule.Match, StaticHeaderRule.Match and StaticRangeRule.MatchThis includes alternatives, parameters, optional, extensions and wildcard. Rate limit and Static files to know the specific value that each area compares.
Hot reload
The full map is recombined during hot relay. Subsequent requests immediately use new routes; a request that has already started retains the status with which it was accepted.
If a pattern is invalid, GOX reports the error and retains the previous valid configuration.
Best practices
- Keep explicit and stable internal destinations.
- It uses names of descriptive parameters.
- Avoid dynamic patterns that unnecessarily overlap.
- Place the optional segments at the end.
- Reserve the wildcard for the final segment.
- Try exact routes, parameters, optional and wildcard separately.