Pattern Syntax¶
The URLPattern syntax follows the WHATWG URLPattern specification. This guide covers the pattern syntax you can use with this extension.
URL Components¶
A URL pattern can match against all components of a URL:
When you provide a full URL pattern like https://example.com/users/:id, the pattern is parsed into components that are matched independently.
Basic Patterns¶
Literal Matching¶
Exact string matching:
-- Matches only this exact URL
SELECT urlpattern_test(
'https://example.com/about',
'https://example.com/about'
); -- true
SELECT urlpattern_test(
'https://example.com/about',
'https://example.com/contact'
); -- false
Wildcards (*)¶
The * wildcard matches any sequence of characters (including empty):
-- Matches any path under /api/
SELECT urlpattern_test('https://example.com/api/*', 'https://example.com/api/users'); -- true
SELECT urlpattern_test('https://example.com/api/*', 'https://example.com/api/v1/users'); -- true
SELECT urlpattern_test('https://example.com/api/*', 'https://example.com/api/'); -- true
Multiple wildcards:
-- Matches /api/{version}/users/{id}
SELECT urlpattern_test(
'https://example.com/api/*/users/*',
'https://example.com/api/v1/users/123'
); -- true
Named Groups¶
Basic Named Groups (:name)¶
Named groups capture a single path segment (up to the next /):
-- :id captures '123'
SELECT urlpattern_test(
'https://example.com/users/:id',
'https://example.com/users/123'
); -- true
-- Extract the captured value
SELECT urlpattern_extract(
'https://example.com/users/:id',
'https://example.com/users/123',
'id'
); -- '123'
Multiple Named Groups¶
SELECT urlpattern_extract(
'https://example.com/api/:version/:resource/:id',
'https://example.com/api/v2/posts/456',
'version'
); -- 'v2'
SELECT urlpattern_extract(
'https://example.com/api/:version/:resource/:id',
'https://example.com/api/v2/posts/456',
'resource'
); -- 'posts'
SELECT urlpattern_extract(
'https://example.com/api/:version/:resource/:id',
'https://example.com/api/v2/posts/456',
'id'
); -- '456'
Named Groups in Other Components¶
Named groups work in any URL component:
-- Hostname
SELECT urlpattern_extract(
'https://:subdomain.example.com/*',
'https://api.example.com/test',
'subdomain'
); -- 'api'
-- Protocol (less common but supported)
SELECT urlpattern_test(
':protocol://example.com/*',
'https://example.com/test'
); -- true
Component-Specific Patterns¶
Protocol¶
-- Match only HTTPS
SELECT urlpattern_test('https://example.com/*', 'https://example.com/test'); -- true
SELECT urlpattern_test('https://example.com/*', 'http://example.com/test'); -- false
-- Match any protocol
SELECT urlpattern_test('*://example.com/*', 'https://example.com/test'); -- true
SELECT urlpattern_test('*://example.com/*', 'http://example.com/test'); -- true
Hostname¶
-- Exact hostname
SELECT urlpattern_test('https://example.com/*', 'https://example.com/test'); -- true
SELECT urlpattern_test('https://example.com/*', 'https://api.example.com/test'); -- false
-- Wildcard subdomain
SELECT urlpattern_test('https://*.example.com/*', 'https://api.example.com/test'); -- true
SELECT urlpattern_test('https://*.example.com/*', 'https://www.example.com/test'); -- true
SELECT urlpattern_test('https://*.example.com/*', 'https://example.com/test'); -- false (no subdomain)
Port¶
-- Specific port
SELECT urlpattern_test('https://example.com:8080/*', 'https://example.com:8080/test'); -- true
SELECT urlpattern_test('https://example.com:8080/*', 'https://example.com:3000/test'); -- false
-- Any port
SELECT urlpattern_test('https://example.com:*/*', 'https://example.com:8080/test'); -- true
Pathname¶
-- Single segment wildcard
SELECT urlpattern_test('https://example.com/users/:id', 'https://example.com/users/123'); -- true
SELECT urlpattern_test('https://example.com/users/:id', 'https://example.com/users/123/edit'); -- false
-- Multi-segment wildcard
SELECT urlpattern_test('https://example.com/files/*', 'https://example.com/files/a/b/c.txt'); -- true
Search (Query String)¶
-- Wildcard query
SELECT urlpattern_test('https://example.com/search?*', 'https://example.com/search?q=test'); -- true
-- Specific query pattern
SELECT urlpattern_test(
'https://example.com/search?q=:query',
'https://example.com/search?q=hello'
); -- true
Hash (Fragment)¶
-- Any hash
SELECT urlpattern_test('https://example.com/page#*', 'https://example.com/page#section1'); -- true
-- Specific hash
SELECT urlpattern_test('https://example.com/page#top', 'https://example.com/page#top'); -- true
SELECT urlpattern_test('https://example.com/page#top', 'https://example.com/page#bottom'); -- false
Pattern Matching Rules¶
Segment Boundaries¶
Named groups (:name) match a single segment by default:
- In pathnames, segments are separated by
/ - In hostnames, segments are separated by
.
-- :id matches only one segment
SELECT urlpattern_test('https://example.com/users/:id', 'https://example.com/users/123'); -- true
SELECT urlpattern_test('https://example.com/users/:id', 'https://example.com/users/123/posts'); -- false
Greedy vs Non-Greedy¶
The * wildcard is greedy and matches as much as possible:
-- * matches 'a/b/c'
SELECT urlpattern_test('https://example.com/*', 'https://example.com/a/b/c'); -- true
Best Practices¶
-
Use full URL patterns for
urlpattern_testto ensure all components are matched: -
Use named groups for extraction rather than trying to parse URLs manually:
-
Be specific about what you want to match to avoid false positives: