Skip to main content
  1. Tutorials/

How to URL-encode in Go with net/url (query, path, full URL)

··3 mins

URL encoding, also known as percent-encoding, makes URLs safe to transmit by encoding reserved characters. In Go, you handle this with the net/url package. ✅

In this guide, you will encode:

  • query parameters
  • path segments
  • a full URL
  • and learn how to decode when needed

What You’ll Learn #

  • How to encode query parameters with url.QueryEscape and url.Values
  • How to encode path segments with url.PathEscape
  • How to build a full encoded URL safely
  • How to decode values with QueryUnescape and PathUnescape

A quick URL anatomy #

scheme://host:port/path?query

Encode the query part of the URL #

The url.QueryEscape() function from the net/url package is used to encode a string placed inside a URL query.

package main

import (
    "fmt"
    "net/url"
)

func main() {
    query1Val := url.QueryEscape("ab+c")
    query2Val := url.QueryEscape("de$f")

    fmt.Println(query1Val)
    fmt.Println(query2Val)
}

Output:

ab%2Bc
de%24f

To create an encoded multiple key-value query parameters string, use the url.Values structure from the net/url package.

package main

import (
    "fmt"
    "net/url"
)

func main() {
    queryValues := url.Values{}
    queryValues.Add("query", "ab+c")
    queryValues.Add("query2", "de$f")
    encodedQuery := queryValues.Encode()
    fmt.Println(encodedQuery)
}

Output:

query=ab%2Bc&query2=de%24f

Encode the path part of the URL #

The url.PathEscape() function from the net/url package is used to encode a string that is placed inside a URL path segment. The path segment is encoded differently from the query, for example, the + character is allowed in the path, and should be encoded in the query.

package main

import (
    "fmt"
    "net/url"
)

func main() {
    path := url.PathEscape("foo+bar!")
    fmt.Println(path)
}

Output:

foo+bar%21

Build a full encoded URL #

There are two ways to construct a full encoded URL. You can create it manually by joining different parts of the URL, where the query and path parts are escaped with the previously used functions.

package main

import (
    "fmt"
    "net/url"
)

func main() {
    // build url manually
    host := "https://example.com/"
    path := url.PathEscape("foo+bar!")
    query1Val := url.QueryEscape("ab+c")
    query2Val := url.QueryEscape("de$f")
    query := fmt.Sprintf("query=%s&query2=%s", query1Val, query2Val)
    fmt.Printf("%s %s%s?%s\n", "Manually built URL:", host, path, query)
}

Output:

Manually built URL: https://example.com/foo+bar%21?query=ab%2Bc&query2=de%24f

However, it is generally better idea to build the encoded URL by using the url.URL structure. This way is easier and less error-prone than manually constructing the resulting URL. You just need to set the Scheme, Host, Path of the URL and build the RawQuery string by encoding query parameters inside the url.Values struct.

package main

import (
    "fmt"
    "net/url"
)

func main() {
    // build url using url.URL struct
    exampleURL := &url.URL{
        Scheme: "https",
        Host:   "example.com",
        Path:   "/foo+bar!",
    }
    queryValues := url.Values{}
    queryValues.Add("query", "ab+c")
    queryValues.Add("query2", "de$f")
    exampleURL.RawQuery = queryValues.Encode()
    fmt.Printf("%s %s\n", "URL built using url.URL struct:", exampleURL)
}
URL built using url.URL struct: https://example.com/foo+bar%21?query=ab%2Bc&query2=de%24f

Use these when you need to read encoded values back:

package main

import (
    "fmt"
    "net/url"
)

func main() {
    decodedQuery, _ := url.QueryUnescape("ab%2Bc")
    decodedPath, _ := url.PathUnescape("foo+bar%21")

    fmt.Println(decodedQuery)
    fmt.Println(decodedPath)
}

Output:

ab+c
foo+bar!

Common mistakes #

❌ Using QueryEscape for a path segment:

path := url.QueryEscape("foo+bar!") // "+" becomes "%2B" (not what you want)

✅ Use PathEscape for path segments:

path := url.PathEscape("foo+bar!")

❌ Manually concatenating query strings without encoding:

query := "q=go+tips&tag=c#"

✅ Use url.Values:

values := url.Values{}
values.Add("q", "go+tips")
values.Add("tag", "c#")
query := values.Encode()

Best practices #

  • Use url.Values for query strings to avoid subtle encoding bugs.
  • Use url.URL to assemble full URLs safely.
  • Encode only the parts you control, not the entire URL string.

Tested with Go 1.25+ | Last verified: December 2025 🎉