
Security News
upm Launches as a Fast, Tiny Package Manager Written in TypeScript
upm uses Node.js to deliver fast npm installs in about 250 KB, with a JavaScript API and security defaults.
@remix-run/route-pattern
Advanced tools
Type-safe URL matching and href generation for JavaScript. route-pattern supports path variables, wildcards, optionals, search constraints, and full-URL patterns with predictable ranking.
npm i remix
import { createMultiMatcher } from 'remix/route-pattern/match'
let matcher = createMultiMatcher<{ name: string }>()
matcher.add('blog/:slug', { name: 'blog-post' })
matcher.add('api(/v:version)/*path', { name: 'api' })
matcher.add('http(s)://:region.cdn.com/assets/*file.:ext', { name: 'assets' })
let match = matcher.match('https://example.com/blog/v3')
match?.pattern.toString()
// /blog/:slug
match?.params
// { slug: 'v3' }
match?.data
// { name: 'blog-post' }
import { createHref } from 'remix/route-pattern/href'
createHref('blog/:slug', { slug: 'v3' })
// '/blog/v3'
createHref('api(/v:version)/*path', { version: '2', path: 'users/profile' })
// '/api/v2/users/profile'
createHref('http(s)://:region.cdn.com/assets/*file.:ext', {
region: 'us-west',
file: 'images/logo',
ext: 'png',
})
// 'https://us-west.cdn.com/assets/images/logo.png'
remix/route-pattern - Parse and stringify patterns.
remix/route-pattern/href - Generate hrefs for patterns with type safe params.
remix/route-pattern/match - Match against one pattern with type inference for params. Or match against many patterns with deterministic ranking and attached data.
remix/route-pattern/join - Combine two patterns into one. Override protocol, hostname, port. Join pathnames. Merge search constraints.
remix/route-pattern/specificity - Rank matches by specificity.
For in-depth reference, visit the route-pattern API docs
Protocol must be http, https, or http(s):
'https://example.com' // matches https://example.com
'http(s)://example.com' // matches http://example.com, https://example.com
Variables capture dynamic segments using :name:
'users/:id' // matches /users/123
'blog/:year-:month-:day/:slug' // matches /blog/2024-01-15/hello
Wildcards match multi-segment paths using *name:
'files/*path' // matches /files/images/logo.png
'node_modules/*package/dist/index.js' // matches /node_modules/@remix-run/router/dist/index.js
'files/*' // matches any path under /files, but doesn't capture the wildcard value
Optionals make parts optional using ():
'api(/v:version)/users' // matches /api/users, /api/v2/users
'blog/:slug(.html)' // matches /blog/hello, /blog/hello.html
'docs(/guides/:category)' // matches /docs, /docs/guides/routing
'api(/v:major(.:minor))' // matches /api, /api/v2, /api/v2.1
While variables, wilcards, and optionals are most prevalent in pathnames, you can also use them in hostnames:
':tenant.example.com/dashboard' // matches acme.example.com/dashboard
'(www.)example.com/blog/:slug(.html)' // matches example.com/blog/hello, www.example.com/blog/hello.html
'*.example.com/files/*path' // matches cdn.example.com/files/images/logo.png
'(:locale.)example.com/docs(/:section)' // matches en.example.com/docs, en.example.com/docs/guides
Search constraints narrow matches using ?key or ?key=value:
'search?q' // key must be present
'search?q=routing' // requires ?q=routing exactly
Use createMatcher when you have one pattern and want params inferred from that exact pattern.
import { createMatcher } from 'remix/route-pattern/match'
const url: string | URL = /* ... */
let blogMatcher = createMatcher('blog/:slug')
blogMatcher.match(url)?.params
// Type safe params ^? { slug: string } | undefined
let docsMatcher = createMatcher('://(:tenant.)host.com/docs/*path.:ext')
docsMatcher.match(url)?.params
// Type safe params ^? { tenant: string | undefined, path: string, ext: string } | undefined
Use createMultiMatcher when you need to match many patterns and attach your own data to each match.
import { createMultiMatcher } from 'remix/route-pattern/match'
let matcher = createMultiMatcher<string>()
// Any data type you want! 👆
matcher.add('/', 'home')
matcher.add('blog/:slug', 'blog-post')
matcher.add('api(/v:version)/*path', 'api')
matcher.match('https://example.com/blog/v3')
// { params: { slug: 'v3' }, data: 'blog-post' }
matcher.match('https://example.com/api/v2/users/profile')
// { params: { version: '2', path: 'users/profile' }, data: 'api' }
The matched pattern is only known at runtime, so matched params are not inferred when matching with createMultiMatcher.
When multiple patterns match the same URL, route-pattern chooses the most specific match deterministically. Matches are ranked left-to-right, character-by-character:
This is the same ranking used by createMultiMatcher.
For advanced use cases, /specificity provides comparison utilities: lessThan, greaterThan, equal, descending, ascending, compare.
For example:
import { createMultiMatcher } from 'remix/route-pattern/match'
import { descending } from 'remix/route-pattern/specificity'
let matcher = createMultiMatcher()
matcher.add('files/*path', null)
matcher.add('files/:name', null)
matcher.add('files/readme.md', null)
let matches = matcher.matchAll('https://example.com/files/readme.md')
matches.sort(descending).map((match) => match.pattern.toString())
// ['/files/readme.md', '/files/:name', '/files/*path']
createHref turns a pattern and params into a URL string.
Required variables and wildcards must be provided, while params inside optional groups may be omitted.
import { createHref } from 'remix/route-pattern/href'
createHref('blog/:slug', { slug: 'v3' })
// '/blog/v3'
createHref('api(/v:version)/*path', { path: 'users/profile' })
// '/api/users/profile'
createHref('api(/v:version)/*path', { version: '2', path: 'users/profile' })
// '/api/v2/users/profile'
createHref('http(s)://:region.cdn.com/assets/*file.:ext', {
region: 'us-west',
file: 'images/logo',
ext: 'png',
})
// 'https://us-west.cdn.com/assets/images/logo.png'
createHref('blog/:slug?ref=docs', { slug: 'v3' }, { utm_source: 'newsletter' })
// '/blog/v3?utm_source=newsletter&ref=docs'
Note: optional groups without params are included in the generated href:
createHref('todos(/new)')
// '/todos/new'
createHref('products(.json)')
// '/products.json'
You can explicitly parse and stringify patterns:
import { RoutePattern } from 'remix/route-pattern'
let pattern = RoutePattern.parse('://example.com/blog/:slug')
// ^? RoutePattern
pattern.toString()
// '://example.com/blog/:slug'
pattern.toJSON()
// { hostname: 'example.com', pathname: 'blog/:slug', ... }
All APIs that take a pattern arg accept string or a parsed RoutePattern.
TIP: For high-performance scenarios, you can parse patterns ahead of time to avoid reparsing them on every call.
joinPatterns builds a new pattern from a base pattern.
import { joinPatterns } from 'remix/route-pattern/join'
let user = joinPatterns('users', ':id')
user.toString()
// '/users/:id'
let apiUser = joinPatterns('api(/v:version)', '://remix.run/users/:id')
apiUser.toString()
// '://remix.run/api(/v:version)/users/:id'
/ in between as necessaryBenchmarks live in bench/.
See LICENSE
FAQs
Match and generate URLs with strong typing
The npm package @remix-run/route-pattern receives a total of 1,061,030 weekly downloads. As such, @remix-run/route-pattern popularity was classified as popular.
We found that @remix-run/route-pattern demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.

Security News
upm uses Node.js to deliver fast npm installs in about 250 KB, with a JavaScript API and security defaults.

Company News
Socket is joining the OpenJS Security Stewardship Program to fund Node.js vulnerability research, maintainer remediation, and security releases.

Security News
Two compromised GitHub Actions were re-enabled with malicious tags intact, exposing thousands of downstream repositories to Mini Shai-Hulud.