valid-url
valid-url is a tiny CommonJS module with four string-checking functions. isUri accepts any syntactically plausible RFC 3986 scheme, while isHttpUri, isHttpsUri, and isWebUri narrow that to absolute web addresses. A successful call returns the original string and a failed call returns undefined. It performs no network request, DNS lookup, normalization, or reachability check. The implementation was translated from an old Perl module and is best understood as a lightweight legacy input filter, not a modern URL parser or a security control.
Keep it only when compatibility with an existing CommonJS call site matters. New code should normally use the built-in URL class or a maintained validator, especially when the address comes from an untrusted user.
Use it if
- You maintain CommonJS code that already depends on its return-string-or-undefined contract
- You need a dependency-free check for absolute HTTP and HTTPS strings and can accept its deliberately practical, older rules
- You need to distinguish generic URIs such as mailto and urn from web URLs with four very small functions
- You support an old Node runtime where relying on the current WHATWG URL API is not an option
- You are starting modern Node code: the built-in URL constructor parses and validates without adding a package, while valid-url's last npm release was in 2013
- You need TypeScript declarations or ESM exports: 1.0.9 ships one CommonJS index.js, has no types field, and exposes no module entry
- You need strict host or port validation: the current implementation accepts strings such as https://_ and https://127.0.0.1:99999 because it barely checks the authority component
- You accept internationalized domain names directly: its illegal-character expression rejects Unicode hostnames unless callers convert them to ASCII form first
- You are defending against SSRF, redirects, or malicious destinations: the README says it does not check accessibility or whether a URI makes sense, and the package performs no DNS or IP-range checks
Setup reality
npm install valid-url adds no runtime dependencies and no configuration files, native builds, environment variables, or peer dependencies. The package is CommonJS only, so the documented shape is const validUrl = require('valid-url'); ESM projects may use a default import through Node interoperability, but named ESM imports are not an advertised interface. There are no bundled TypeScript declarations, so a typed project needs @types/valid-url or a small local declaration. The first surprise is the return type: every function returns the original string on success and undefined on failure, not a boolean. Coerce with Boolean(...) when an API expects true or false. The second is scope. isWebUri requires an absolute http:// or https:// address, so /account and example.com fail. isUri is broader and accepts schemes such as mailto, tel, urn, and javascript, so it is the wrong function for links that will be opened in a browser. Host validation is shallow, ports are not range-checked, Unicode is rejected, and credentials in an authority are accepted. If the value crosses a trust boundary, parse it with the platform URL class after this check, allowlist protocols and hosts, resolve DNS where relevant, and apply redirect checks separately. The test suite uses a very old Tap version and the repository has no current CI signal, which matters if you plan to fork or patch it.
Patterns
Accept an absolute HTTP or HTTPS URLcheck-web-url
const validUrl = require('valid-url');
const value = 'https://example.com/docs?q=node';
if (validUrl.isWebUri(value)) {
console.log('accepted', value);
}Success is the original string, not true; failure is undefined. Relative paths and bare domains are rejected.
Require HTTPS specificallyrequire-https
const validUrl = require('valid-url');
function requireHttps(value) {
if (!validUrl.isHttpsUri(value)) {
throw new TypeError('Expected an absolute HTTPS URL');
}
return value;
}isHttpsUri rejects http:// values, but it does not check the certificate, host reachability, or redirect destination.
Check a non-web URIcheck-generic-uri
const validUrl = require('valid-url');
for (const value of ['mailto:team@example.com', 'tel:+1-816-555-1212']) {
if (validUrl.isUri(value)) console.log(value);
}isUri accepts any plausible scheme, including javascript:. Do not use it as an allowlist for clickable links.
Wrap the string result as a booleanreturn-boolean
const validUrl = require('valid-url');
function isAbsoluteWebUrl(value) {
return typeof value === 'string' && Boolean(validUrl.isWebUri(value));
}The typeof guard avoids passing arbitrary request-body values into an old string-oriented API.
Filter a list to web URLsfilter-url-list
const validUrl = require('valid-url');
const candidates = ['https://example.com', '/local', 'mailto:a@b.test'];
const webUrls = candidates.filter((value) => validUrl.isWebUri(value) !== undefined);filter receives the original string as the truthy result. Use an explicit undefined comparison if that contract should be obvious to readers.
Validate a required form fieldvalidate-form-field
const validUrl = require('valid-url');
function validateHomepage(input) {
const value = String(input ?? '').trim();
if (!validUrl.isWebUri(value)) {
return { ok: false, error: 'Enter a full http:// or https:// URL' };
}
return { ok: true, value };
}Trimming is caller policy; the library rejects spaces rather than normalizing them.
Parse the accepted value with the platform URL APIparse-after-check
const validUrl = require('valid-url');
function parseWebUrl(value) {
if (!validUrl.isWebUri(value)) throw new TypeError('Invalid web URL');
const url = new URL(value);
if (Number(url.port) > 65535) throw new TypeError('Invalid port');
return url;
}valid-url does not range-check ports or give you parsed components. In modern Node, URL alone is usually enough.
Reject embedded usernames and passwordsreject-url-credentials
const validUrl = require('valid-url');
function publicLink(value) {
if (!validUrl.isWebUri(value)) return undefined;
const url = new URL(value);
if (url.username || url.password) return undefined;
return url.href;
}The package accepts user:password@authority syntax. Reject it explicitly before logging, storing, or displaying public links.
Allow only known HTTPS hostsallowlist-host
const validUrl = require('valid-url');
const allowed = new Set(['api.example.com', 'cdn.example.com']);
function isAllowedEndpoint(value) {
if (!validUrl.isHttpsUri(value)) return false;
const url = new URL(value);
return allowed.has(url.hostname);
}A syntax check does not prevent SSRF. For server-side requests, also handle DNS resolution, private IP ranges, redirects, and rebinding.
Reject a bad URL in Express middlewareexpress-request-validation
const validUrl = require('valid-url');
function requireCallbackUrl(req, res, next) {
const value = req.body.callbackUrl;
if (typeof value !== 'string' || !validUrl.isHttpsUri(value)) {
return res.status(400).json({ error: 'callbackUrl must use https' });
}
req.callbackUrl = value;
next();
}Do not fetch the URL on this check alone. Apply destination and redirect policy before any outbound request.
Handle relative links separatelyaccept-relative-or-absolute
const validUrl = require('valid-url');
function resolveLink(value, base) {
if (validUrl.isWebUri(value)) return new URL(value);
if (value.startsWith('/') && !value.startsWith('//')) {
return new URL(value, base);
}
throw new TypeError('Unsupported link');
}All four package methods reject ordinary relative paths. Keep relative-link policy explicit instead of pretending they are malformed URLs.
Convert an internationalized hostname before checkingsupport-unicode-host
const validUrl = require('valid-url');
const { domainToASCII } = require('node:url');
const host = domainToASCII('例え.テスト');
const value = `https://${host}/`;
if (!host || !validUrl.isHttpsUri(value)) throw new TypeError('Invalid URL');valid-url rejects non-ASCII characters. The native URL constructor already performs this conversion, so prefer it when legacy compatibility is not required.
Alternatives
| Package | Registry | Pick it when |
|---|---|---|
| validator | npm | You need maintained string validation with configurable URL rules and many adjacent validators |
| is-url-superb | npm | You want a small boolean URL predicate with a current package surface |
| url-regex-safe | npm | You need safe URL matching inside larger text as well as whole-string checks |