API reference › @evolu/common › Type › Url

const Url: brand(
  "Url",
  String,
  (value: string) =>
    canonicalizeUrl(value) === value
      ? ok()
      : err<UrlError>({ type: "Url", value }),
  formatUrlError,
);

Defined in: packages/common/src/Type.ts:9709

Canonical absolute URL String.

A Url is a URL as the WHATWG URL Standard serializes it, so new URL(value).href equals the value, such as https://example.com/ for https://example.com. Like DateIso, it has one spelling per URL on an engine, so equal URLs are equal strings there. Url does not normalize; use UrlFromString to convert other spellings, such as user input. Relative URLs are rejected.

Url accepts any scheme, including javascript:, whose links run code when followed. Use HttpUrl for links. Url sets no maximum length, and a data: URL can hold a whole file; compose maxLength(2048)(Url) or another limit when one matters, such as for a database column.

Url validates with the platform's URL, which browsers and Node.js provide, and which Expo SDK 58 and later installs on React Native. React Native without Expo has its own URL, which accepts strings that are not URLs, so install one that follows the standard, such as whatwg-url-minimum 0.2 or later, which Expo installs, as the react-native example does without replacing React Native's URL.createObjectURL.

Engines don't always parse a URL the same way. Chromium percent-encodes | in a path, which the others keep, and accepts a space in a host, which they reject. Firefox rejects some xn-- hosts that the others accept, and whatwg-url-minimum accepts some right-to-left hosts that the others reject. Revisions of the standard change the serialization too, as when it began to percent-encode ^ in a path in 2025. No engine decodes a percent-escape, so the same URL can be two different strings, and a Url from one device can fail validation on another device or after an engine update. Evolu does not validate the values other devices write, so where a valid Url matters, transform a value read from the database with UrlFromString and handle its error. It doesn't make another engine's spelling equal to this one's.

Example

import { assertErr, assertOk, Url } from "@evolu/common";

assertOk(Url.fromUnknown("https://example.com/"), "https://example.com/");

assertErr(Url.fromUnknown("https://example.com"), {
  type: "Url",
  value: "https://example.com",
});