URL manipulation done right
The url library handles everything URL-related — encoding, decoding, parsing, building, and generating slugs.
Function reference
| Function | Example | Result |
|---|---|---|
url.encode(s) |
url.encode("hello world") |
"hello+world" |
url.decode(s) |
url.decode("hello+world") |
"hello world" |
url.rawencode(s) |
url.rawencode("hello world") |
"hello%20world" |
url.rawdecode(s) |
url.rawdecode("hello%20world") |
"hello world" |
url.parse(url) |
url.parse("https://ex.com/path?q=1") |
{ scheme, host, path, query } |
url.build(parts) |
url.build({ host, path, query }) |
"example.com/test?a=1" |
url.slug(s) |
url.slug("Hello World! 2026") |
"hello-world-2026" |
url.redirect(url) |
url.redirect("/dashboard") |
Sends 302 redirect immediately |
url.encode vs url.rawencode
-- Form encoding: spaces → +
url.encode("hello world") → "hello+world"
-- RFC 3986: spaces → %20
url.rawencode("hello world") → "hello%20world"
Use rawencode for URL paths, encode for query strings.
Parsing a URL
local parts = url.parse("https://example.com:8080/path/to/page?q=lua&page=2")
-- {
-- scheme = "https",
-- host = "example.com",
-- port = "8080",
-- path = "/path/to/page",
-- query = "q=lua&page=2"
-- }
print(parts.host) -- "example.com"
Building a URL
local link = url.build({
scheme = "https",
host = "mysite.wapka.site",
path = "/blog/" .. slug,
query = "utm_source=newsletter"
})
-- → "https://mysite.wapka.site/blog/hello-world?utm_source=newsletter"
Note:
url.build()supportsscheme,host,path, andquerykeys only. Port, fragment, and userinfo are not handled.
Generating slugs for SEO
-- Create clean URLs from titles
local title = "How to Build a Lua API in 10 Minutes"
local slug = url.slug(title)
-- → "how-to-build-a-lua-api-in-10-minutes"
-- Use it in a route
app:get("/blog/" .. slug, postHandler)
Quick redirect
-- Redirect and stop execution immediately
url.redirect("/login")
-- For custom status codes, use ctx:redirect instead
ctx:redirect("/new-location", 301)
Practical: building a search URL
app:post("/search", function(ctx)
local q = url.encode(req.post.query)
return ctx:redirect("/search?q=" .. q)
end)
app:get("/search", function(ctx)
local query = req.query.q
if not query then
return ctx:render("search", { results = {} })
end
local results = api.dataset.find("articles", {
filter = { title = { like = "%" .. query .. "%" } }
})
return ctx:render("search", {
query = query,
results = results.items
})
end)
Next: Encoder — convert data between formats.