Skip to main content
Fuego uses a file-system based router inspired by Next.js App Router. Your file structure defines your routes.

Basic Routing

Create route.go files to define API endpoints: This creates:
  • app/api/users/route.go/api/users
  • app/api/posts/route.go/api/posts
  • app/route.go/

Handler Functions

Export functions named after HTTP methods:
package users

import "github.com/abdul-hamid-achik/fuego/pkg/fuego"

// GET /api/users
func Get(c *fuego.Context) error {
    return c.JSON(200, []string{"alice", "bob"})
}

// POST /api/users
func Post(c *fuego.Context) error {
    return c.JSON(201, map[string]string{"status": "created"})
}

// PUT /api/users
func Put(c *fuego.Context) error {
    return c.JSON(200, map[string]string{"status": "updated"})
}

// PATCH /api/users
func Patch(c *fuego.Context) error {
    return c.JSON(200, map[string]string{"status": "patched"})
}

// DELETE /api/users
func Delete(c *fuego.Context) error {
    return c.NoContent()
}

// HEAD /api/users
func Head(c *fuego.Context) error {
    return c.NoContent()
}

// OPTIONS /api/users
func Options(c *fuego.Context) error {
    c.SetHeader("Allow", "GET, POST, PUT, PATCH, DELETE")
    return c.NoContent()
}
All handlers must have the signature func(c *fuego.Context) error. Invalid signatures are skipped with a warning.

Dynamic Routes

Use [param] folders for dynamic segments: This creates:
  • /api/users - static route
  • /api/users/:id - dynamic route
package users

import "github.com/abdul-hamid-achik/fuego/pkg/fuego"

// GET /api/users/:id
func Get(c *fuego.Context) error {
    id := c.Param("id")
    return c.JSON(200, map[string]string{"id": id})
}

Multiple Parameters

Maps to /api/orgs/:orgId/teams/:teamId
func Get(c *fuego.Context) error {
    orgId := c.Param("orgId")
    teamId := c.Param("teamId")
    return c.JSON(200, map[string]string{
        "orgId":  orgId,
        "teamId": teamId,
    })
}

Catch-All Routes

Use [...param] for catch-all routes: Maps to /api/docs/*
func Get(c *fuego.Context) error {
    // /api/docs/api/users/create → slug = "api/users/create"
    slug := c.Param("slug")
    segments := strings.Split(slug, "/")
    return c.JSON(200, map[string]any{
        "slug":     slug,
        "segments": segments,
    })
}
Examples:
  • /api/docs/helloslug = "hello"
  • /api/docs/2024/01/my-postslug = "2024/01/my-post"

Optional Catch-All

Use [[...param]] for optional catch-all (matches with or without segments): Matches:
  • /api/shop → categories = ""
  • /api/shop/electronics → categories = "electronics"
  • /api/shop/electronics/phones → categories = "electronics/phones"

Route Groups

Use (groupname) folders to organize without affecting URLs: Creates:
  • /api/about (not /api/marketing/about)
  • /api/blog
  • /api/products
  • /api/cart
Route groups are great for organizing code and applying shared middleware without affecting URLs.

Private Folders

Folders starting with _ are ignored: The _components and _utils folders are ignored by the router.

Route Priority

Routes are matched in order of specificity:
  1. Static routes (highest priority)
    • /api/users/me matches before /api/users/:id
  2. Dynamic routes
    • /api/users/:id matches after static routes
  3. Catch-all routes (lowest priority)
    • /docs/* matches last
Example:
GET /api/users/me   → matches /api/users/me (static)
GET /api/users/123  → matches /api/users/:id (dynamic)
GET /docs/anything  → matches /docs/* (catch-all)

Viewing Routes

Use the CLI to list all routes:
fuego routes
Output:
  Fuego Routes

  GET     /                             app/route.go
  GET     /api/health                   app/api/health/route.go
  GET     /api/users                    app/api/users/route.go
  POST    /api/users                    app/api/users/route.go
  GET     /api/users/{id}               app/api/users/[id]/route.go

  Total: 5 routes
Add --json for machine-readable output:
fuego routes --json

Handler Signature

All handlers must have this signature:
func HandlerName(c *fuego.Context) error
Invalid signatures are skipped with a warning. Make sure your handlers match the expected signature.

Complete Example

Routes created:
MethodRouteFile
GET/app/page.templ
GET/api/healthapp/api/health/route.go
GET,POST/api/usersapp/api/users/route.go
GET,PUT,DELETE/api/users/:idapp/api/users/[id]/route.go
GET/api/posts/*app/api/posts/[...slug]/route.go
GET,PUT/api/settingsapp/api/(admin)/settings/route.go

Next Steps