diff --git a/packages/url/index.js b/packages/url/index.js
new file mode 100644
index 0000000..f0be7db
--- /dev/null
+++ b/packages/url/index.js
@@ -0,0 +1,31 @@
+const { parse } = require('url');
+
+module.exports = function (req) {
+ let url = req.url;
+ if (url === void 0) return url;
+
+ let obj = req._parsedUrl;
+ if (obj && obj._raw === url) return obj;
+
+ obj = {};
+ let c, len=url.length;
+ obj.query = obj.search = null;
+ obj.href = obj.path = obj.pathname = url;
+
+ while (--len) {
+ c = url.charCodeAt(len);
+ if (c === 35) { // #
+ obj = parse(url);
+ break;
+ } else if (c === 63) { // ?
+ obj.search = url.substring(len);
+ obj.query = obj.search.substring(1);
+ obj.pathname = url.substring(0, len);
+ break;
+ }
+ }
+
+ obj._raw = url;
+
+ return (req._parsedUrl = obj);
+}
diff --git a/packages/url/package.json b/packages/url/package.json
new file mode 100644
index 0000000..7de68d9
--- /dev/null
+++ b/packages/url/package.json
@@ -0,0 +1,18 @@
+{
+ "name": "@polka/url",
+ "version": "0.0.0",
+ "description": "Super fast, memoized `req.url` parser",
+ "repository": "lukeed/polka",
+ "license": "MIT",
+ "files": [
+ "*.js"
+ ],
+ "author": {
+ "name": "Luke Edwards",
+ "email": "luke@lukeed.com",
+ "url": "https://lukeed.com"
+ },
+ "publishConfig": {
+ "access": "public"
+ }
+}
diff --git a/packages/url/readme.md b/packages/url/readme.md
new file mode 100644
index 0000000..16fa5e3
--- /dev/null
+++ b/packages/url/readme.md
@@ -0,0 +1,81 @@
+# @polka/url [![npm](https://badgen.now.sh/npm/v/@polka/url)](https://npmjs.org/package/@polka/url)
+
+> Super fast, memoized `req.url` parser; _not_ limited to [Polka][polka]!
+
+Parses the `url` from a [`IncomingMessage`](https://nodejs.org/api/http.html#http_class_http_incomingmessage) request.
+
+If the `req.url` contains a hash (`#`) then the native [`url.parse`](https://nodejs.org/api/url.html#url_url_parse_urlstring_parsequerystring_slashesdenotehost) will be used, returning a complete [`Url`](https://nodejs.org/api/url.html#url_class_url).
Otherwise, the return object will only contain the following keys: `search`, `query`, `pathname`, `path`, `href`, and `_raw`.
+
+> **Note:** This library does not process `protocol`, `hostname`, `port`, etc.
This is because the incoming `req.url` value only begins with the path information.
+
+Parsed requests will be mutated with a `_parsedUrl` key, containing the returned output. This is used for future memoization, so as to avoid parsing the same `url` value multiple times.
+
+## Install
+
+```
+$ npm install --save @polka/url
+```
+
+## Usage
+
+```js
+const parse = require('@polka/url');
+
+let req = { url: '/foo/bar?fizz=buzz' };
+let foo = parse(req);
+//=> { search: '?fizz=buzz',
+//=> query: 'fizz=buzz',
+//=> pathname: '/foo/bar',
+//=> path: '/foo/bar?fizz=buzz',
+//=> href: '/foo/bar?fizz=buzz',
+//=> _raw: '/foo/bar?fizz=buzz' }
+
+// Attaches result for future memoization
+assert.deepEqual(foo, req._parsedUrl); //=> true
+
+// Process a request w/ a hashtag
+req = { url: '/foo/bar?fizz=buzz#hello' };
+let bar = parse(req);
+//=> Url {
+//=> protocol: null,
+//=> slashes: null,
+//=> auth: null,
+//=> host: null,
+//=> port: null,
+//=> hostname: null,
+//=> hash: '#hello',
+//=> search: '?fizz=buzz',
+//=> query: 'fizz=buzz',
+//=> pathname: '/foo/bar',
+//=> path: '/foo/bar?fizz=buzz',
+//=> href: '/foo/bar?fizz=buzz#hello',
+//=> _raw: '/foo/bar?fizz=buzz#hello' }
+
+// Also attaches result for future memoization
+assert.deepEqual(bar, req._parsedUrl); //=> true
+```
+
+## API
+
+### url(req)
+Returns: `Object` or `undefined`
+
+> **Important:** The `req` must have a `url` key, otherwise `undefined` will be returned.
If no input is provided at all, a `TypeError` will be thrown.
+
+#### req
+Type: `IncomingMessage`
+
+The incoming HTTP request (`req`).
+
+
+
+## Support
+
+Any issues or questions can be sent to the [Polka][polka] repo, but please specify that your inquiry is about `@polka/url` specifically.
+
+
+## License
+
+MIT © [Luke Edwards](https://lukeed.com)
+
+[polka]: https://github.com/lukeed/polka