valid-url review
valid-url 1.0.9 exports 4 URI syntax checks: generic, HTTP, HTTPS, and either web protocol. A passing call returns a reconstructed string; failure returns `undefined`. It never opens a connection, resolves DNS, checks a certificate, normalizes a destination for policy, or proves that the host exists. The code is a line-by-line JavaScript translation of an older Perl validator. Version 1.0.9 updated documentation and package metadata without changing the runtime checker. Our browser build measured 1.8 KB minified and 0.9 KB gzipped, but the npm tarball does not declare a license.
valid-url 1.0.9 installed in 0.5 seconds with zero audit findings, but its tarball has no declared license and its host rules accept `_` plus out-of-range ports. Keep it for an exact legacy contract; new trusted-boundary code should parse with `URL` and enforce protocol, hostname, DNS, IP-range, credential, and redirect policy separately.
We installed it
| Install | ✓ · 0.5s | 1 package on disk · 1 MB |
| Import | ✓ | ESM import works · require() works · CommonJS package |
| Browser | 0.9 KB | gzipped (1.8 KB minified), bundled with esbuild |
| Types | — | no TypeScript types found |
| Known vulns | 0 | 0 critical · 0 high · 0 moderate · 0 low (npm audit) |
Answers from our run
Does valid-url install cleanly?
Yes. In a fresh container with an empty cache, npm install valid-url finished in 0.5s, leaving 1 package and 1 MB on disk. npm audit reported no known vulnerabilities.
How much does valid-url add to a browser bundle?
0.9 KB gzipped (1.8 KB minified) when the whole package is bundled for the browser with esbuild. Importing only part of it is usually smaller.
Does valid-url work with both ESM and CommonJS?
Yes. Both import 'valid-url' and require('valid-url') worked in Node 22 in our run. The package is published as CommonJS.
Does valid-url include TypeScript types?
No type declarations were found in our install, so TypeScript users need their own declarations.
valid-url or validator: which should you use?
validator: Choose it for configurable, maintained URL string rules alongside other input validators. valid-url 1.0.9 installed in 0.5 seconds with zero audit findings, but its tarball has no declared license and its host rules accept _ plus out-of-range ports.
When should you not use valid-url?
You are writing current Node or browser code. The platform URL constructor parses components, validates ports, and handles internationalized hosts without this dependency.
Use it if
- A legacy CommonJS call site depends on `string | undefined` from `isUri`, `isHttpUri`, `isHttpsUri`, or `isWebUri`.
- You need a tiny dependency-free prefilter for absolute ASCII HTTP and HTTPS strings, with stricter policy applied afterward.
- Old code must preserve both camelCase method names and the package's snake_case aliases.
- Generic URI schemes and web URLs must be checked separately, and the broad `isUri` behavior is understood.
- You are writing current Node or browser code. The platform `URL` constructor parses components, validates ports, and handles internationalized hosts without this dependency.
- The result controls a server-side fetch. `isWebUri` accepts credentials and performs no DNS, private-address, redirect, or rebinding checks, so it is not an SSRF defense.
- Host syntax must be strict. Version 1.0.9 accepts authorities such as `https://_` and does not validate the numeric port range.
- Unicode domain input should work directly. Its allowed-character expression rejects non-ASCII hostnames before parsing.
- TypeScript declarations, an ESM entry, or an exports map are required. Our package inspection found none.
- A declared package license is mandatory for procurement. The measured 1.0.9 tarball reports its license as unknown.
Setup reality
We installed valid-url 1.0.9 in 0.5 seconds, leaving one package and 1 MB on disk. The package is 56 KB unpacked and has zero direct dependencies plus zero peers. npm audit found zero known vulnerabilities. It is CommonJS without an exports map; require() and ESM import worked in Node 22. No TypeScript declarations were present, and the package metadata did not identify a license.
There are no credentials, native builds, or config files. The integration surprise is the return contract: success gives back a string and failure gives undefined, rather than returning a boolean. Boolean(validUrl.isWebUri(value)) is appropriate when a boolean is needed. isWebUri accepts only absolute http:// and https:// values, so /account and example.com fail. isUri accepts a wider scheme grammar and can accept javascript:; do not use that broad function as a clickable-link allowlist.
The authority check is shallow. Version 1.0.9 separates a numeric-looking port but never checks whether it is at most 65535, allows embedded username and password text, and does not verify a real hostname. Its character filter rejects Unicode, while percent escapes receive only basic shape checks. Parse accepted values with new URL, allowlist protocols and destinations, reject credentials where needed, and normalize before equality or cache-key use.
Our browser bundle was 1.8 KB minified and 0.9 KB gzipped. Small size does not repair the 2013 rule set. The npm release dates to July 31, 2013; GitHub's last push was September 17, 2021. Version 1.0.9 itself only revised README and package files after 1.0.8. For current code, use the platform parser or a maintained validator. Keep this package when changing its old return and acceptance behavior would break a tested compatibility path.
Patterns
Accept absolute HTTP or HTTPS input check-web-url
const validUrl = require('valid-url')
const input = 'https://example.com/docs?q=node'
if (validUrl.isWebUri(input)) {
console.log('accepted', input)
}In 1.0.9 success returns the URL string and failure returns `undefined`; relative paths and bare domains fail.
Require the HTTPS scheme require-https
function requireHttps(input) {
const accepted = validUrl.isHttpsUri(input)
if (accepted === undefined) throw new TypeError('absolute HTTPS URL required')
return accepted
}`isHttpsUri` checks syntax only and does not verify the certificate, hostname, network route, or redirect target.
Recognize a non-web URI check-generic-uri
for (const input of ['mailto:team@example.com', 'tel:+1-202-555-0100']) {
const uri = validUrl.isUri(input)
if (uri !== undefined) console.log(uri)
}`isUri` also accepts dangerous schemes such as `javascript:`; apply a scheme allowlist before creating a link.
Expose a boolean result return-boolean
function isAbsoluteWebUrl(input) {
return typeof input === 'string' && Boolean(validUrl.isWebUri(input))
}The type guard keeps arbitrary body values away from the old string-oriented implementation.
Keep only accepted web strings filter-url-list
const candidates = ['https://example.com', '/local', 'mailto:a@example.com']
const web = candidates.filter((value) => {
return validUrl.isWebUri(value) !== undefined
})An explicit `undefined` check makes the string-return contract visible to readers of the filter.
Validate a full homepage field validate-form-field
function validateHomepage(raw) {
const value = String(raw ?? '').trim()
if (!validUrl.isWebUri(value)) {
return { ok: false, error: 'Include http:// or https://' }
}
return { ok: true, value }
}Trimming is caller behavior; valid-url 1.0.9 does not normalize spaces, casing, paths, or hostnames.
Hand an accepted string to URL parse-components
function parseEndpoint(input) {
if (!validUrl.isHttpsUri(input)) throw new TypeError('invalid endpoint')
const url = new URL(input)
if (url.username || url.password) throw new TypeError('credentials are forbidden')
return url
}The platform parser supplies structured components and rejects invalid numeric ports that 1.0.9 can accept.
Restrict outbound endpoints by host allowlist-host
const allowedHosts = new Set(['api.example.com', 'cdn.example.com'])
function allowedEndpoint(input) {
if (!validUrl.isHttpsUri(input)) return false
const url = new URL(input)
return !url.username && !url.password && allowedHosts.has(url.hostname)
}This is still incomplete SSRF protection; server fetches also need DNS, private-address, redirect, and rebinding controls.
Handle site-relative paths separately resolve-relative-link
function resolveLink(input, base) {
if (validUrl.isWebUri(input)) return new URL(input)
if (input.startsWith('/') && !input.startsWith('//')) {
return new URL(input, base)
}
throw new TypeError('unsupported link')
}The package's 4 checks reject ordinary relative paths, so relative-link policy belongs outside the validator.
Parse an internationalized hostname natively convert-unicode-host
const url = new URL('https://例え.テスト/')
console.log(url.hostname)valid-url 1.0.9 rejects Unicode characters; `URL` converts the hostname to its ASCII representation without this package.
Alternatives
| Package | Registry | Pick it when |
|---|---|---|
| validator | npm | Choose it for configurable, maintained URL string rules alongside other input validators. |
| is-url-superb | npm | Choose it for a focused boolean predicate with a current package surface. |
| url-regex-safe | npm | Choose it when URLs must also be detected inside larger text with regular-expression safety controls. |
More utils guides
lru-cache · ajv · type-fest · p-limit · find-up · js-yaml · the whole shelf →
How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.

