The TAG stopped working on that specification. Please consult the WICG WebPackage repository for continuing work on this subject.

This document describes an approach for creating packages of files for use on the web. The approach is to package them using a new application/package media type. To access packages related to other files on the web, clients that understand packages of files look for a Link header or (in HTML documents) a <link> element with a new link relation of package. Other formats may define format-specific mechanisms for locating related packages.

The Technical Architecture Group has put together this draft for comment and to indicate future direction. It is likely this draft will be handed on to a task force or working group to go through the rest of the process.

The technical proposals within this draft (namely new media type and link relation) will eventually require review and registration at IETF. That process has not started yet.


Today's websites rely on multiple files. If a user visits they will need to download about 160 files to view the page in its entirety. The HTML page they download at contains references to stylesheets, scripts, images and other files, each of which may contain references to further files themselves. Many of these resources will themselves have been originally developed as separate resources and merged to avoid the client having to make multiple requests: CSS and Javascript files are concatenated together; images are merged and used with CSS spriting. These concatenation and spriting techniques are rudimentary forms of packaging for performance.

The web is becoming more modular. Web components [[components-intro]] provide developers with the means to create reusable components, such as date pickers, carousels or tab layouts, that can be reused in other web pages. These components are defined through HTML, Javascript and CSS but may also require other resources such as images and data to operate. Meanwhile ES6 Modules [[ECMASCRIPT]] will result in smaller, self-contained and cross-referencing Javascript files. This modularity requires packaging for ease of distribution.

Many websites are no longer simple providers of content: they are applications that use web technologies to deliver their user interface. Initiatives such as Firefox OS and Chrome OS demonstrate the potential of trusted, installable applications built with web technologies. To be used in this way, applications must be self-contained packages of resources that can be tested and signed.

Packages of content and data are not only useful for web applications. Digital publishing requires the packaging of content, stylesheets, fonts and media. Data publication typically requires data and metadata to be packaged together. Archiving requires the packaging of whole websites into dated bundles.

There are existing and upcoming solutions to these problems. On the performance side, HTTP/2 includes the facility to push multiple representations to clients as the result of a single request. Providing packages is orthogonal to the use of HTTP/2. Developers who cannot yet use HTTP/2 may find that using packages can provide performance benefits through reducing numbers of requests. All developers will benefit from being able to package modules and components in ways that make them easy to deliver and reuse.

There are also a plethora of packaging formats, such as:

Most of these formats are based on zips, which have three main drawbacks:

This document specifies a new format for packages which does not have these drawbacks: the Streamable Package Format defined in . It defines a package link relation to point to packages from other resources in . But first, in , this document describes patterns of use for packages that address the requirements described in this introduction.

Using Packages

This section demonstrates how package-aware applications could use packages.

Populating Caches

Packages can be used to populate caches associated with multiple URLs without making multiple requests. This may be beneficial in some cases to avoid the latency involved in making multiple connections, particularly for servers and clients that don't support SPDY or HTTP/2.

Packaging can also damage performance: packages may be bloated by more resources than are actually necessary for the requested page, or may be badly ordered such that resources that are required early in the display of a web page are provided late in a package. Packaging is not a silver bullet for performance issues.

Example Scenario

In this scenario, a browser is pointed at the page which returns the HTML:

    <link rel="package" href="/lib/brand.pack" scope="/lib/brand/">
    <link rel="stylesheet" href="/lib/brand/main.css">

As it starts to receive the page, the browser starts to send off requests for other resources. It recognises the rel="package" links (described in ) as meaning that the files referenced by those links contain useful resources for the display of the page. It starts to download them, taking note of their scope (described in ).

When the browser comes to download the resource, it checks to see if that resource is included in the scope of a package. In this case, the URL starts with so the browser can guess that it is included in the package and not make a separate request for the stylesheet.

The package contains the main CSS stylesheet, but also font files and images that are used as background images within the CSS:

Expires: Mon, 07 Apr 2014 00:00:00 GMT

Content-Location: brand/main.css
Content-Type: text/css

@font-face {
  font-family: 'Shop';
  src: url('shop.woff') format('woff');

body {
  background-image: url('images/bg.jpg') no-repeat center center fixed;

Content-Location: brand/shop.woff
Content-Type: application/font-woff
Expires: Mon, 06 Apr 2015 00:00:00 GMT

Content-Location: brand/images/bg.jpg
Content-Type: image/jpeg
Expires: Mon, 06 Apr 2015 00:00:00 GMT


As the package is loaded, the browser cache is populated with the content of, and Because the package is streamed, the browser can use the CSS straight away, but the supporting resources are loaded rapidly after.

A couple of days later, on revisiting the page, the browser notices that its cached copy of has expired. It requests that CSS file separately to update its cache. There is no need to request the font or the background image as these haven't expired.

If we progress further with the 2NN Contents of Related status code, it would be good to add a scenario that shows that in action.


Package-aware caches SHOULD populate their caches using packages that are indicated through:

  • a rel=package Link HTTP header in the response to a request
  • a rel=package <link> tag in an HTML document

The rel=package link relation is described in .

Package-aware caches SHOULD delay requesting resources within the scope of a package that they are downloading, until the package has been processed.

If a package contains another package that is recognised by the package-aware cache, that package SHOULD be used to populate the cache in the same way.

If a package is in the Streamable Package Format (described in ), package-aware caches SHOULD determine the cachability and other characteristics of each part of the package by examining (in order of priority):

  1. the header of the part
  2. the package header
  3. the HTTP headers in the response for the package

If a package is in the Streamable Package Format, package-aware caches should be aware that there may be multiple parts with the same part URL but with different types or languages. Caches should be populated with attention paid to the Vary header to determine which headers are significant. Package-aware caches SHOULD only use the first part with the same content-negotiated characteristics.

Installing Web Applications

Packages can be used to provide installable web applications, both within marketplaces and simply on the web.

Example Scenario

In this scenario, a browser is pointed at It fetches the home page of the site, and sees:

    <link rel="package" href="/" scope="/" type="application/widget">

The browser recognises that there is a rel=package link in the HTML page whose scope is the entirety of the website, and whose type is a package format that it recognises. It pops up a dialog to ask the user whether they would like to install the application locally, and downloads and installs it if the user agrees.


Package-aware installers SHOULD prompt for the installation of packages that are indicated through:

  • a rel=package Link HTTP header in the response to a request
  • a rel=package <link> tag in an HTML document


  1. the package scope is the same as the request URL
  2. the media type of the package is recognised by the installer

The rel=package link relation is described in .

If a package is in the Streamable Package Format (described in ), it SHOULD include a Link header in the package header with rel=describedby to explicitly point to the resource within the package that describes the package. Alternatively, it SHOULD use a rel=start or rel=first to point to the resource which is the starting point for the application (ie the initial page to load). Otherwise, the first part of the package should be a suitable starting point.

Distributing Code Libraries

Packages can be used to distribute code libraries that are made up of multiple components (modules). For this to work smoothly, they need to be recognised by package management systems such as Bower.

Example Scenario

A developer wants to use a time-handling Javascript package within their own code. They point their package management system at the location of the Javascript package, The package management system retrieves the package:

Content-Type: application/package
Link: <component.json>; rel=describedby

Content-Location: component.json
Content-Type: application/json

... package definition ...

Content-Location: time.js
Content-Type: text/javascript
Link: <locale.pack>; rel=package; scope=locale/

... main Javascript ...

Content-Location: locale.pack
Content-Type: application/package

... package of locale-specific data ...


It unpacks the package into the relevant directory on the developer's machine, but also includes the package itself in the developer's file system so that the package can be referenced by the developer in the website itself:

    <link rel="package" href="/scripts/utils/time.pack" scope="/scripts/utils/time" type="application/package">
    <script src="/scripts/utils/time.js"></script>


Package managers that handle Streamable Package Format packages SHOULD unpack nested packages; these indicate implicit dependencies within the package.

Creators of Streamable Package Format packages for distribution SHOULD NOT include a Content-Location header in the package header as this prevents them from being reused in other locations.

Downloading Data For Local Processing

Data on the web often gains context from other, related, data and documentation. Packages can enable data reusers to quickly get hold of all the relevant data and documentation they need in a single, discoverable, bundle, while simultaneously making that data available directly on the web.

This pattern is of particular relevance to the CSV on the Web Working Group.

Example Scenario

An online news report references some recent demographic statistics, pointing to When a data scientist happens on the reference, they fire up their data analysis application and points it at the URL. The HTTP response looks like:

HTTP/1.1 200 OK
Content-Location: /stats/imd.csv
Content-Type: text/csv
Link: <imd.pack>; rel=package

... CSV file ...

The CSV file is standard CSV: it contains no metadata that describes the types or meaning of any of the columns that it contains, or about the codes that have been used to identify the geographies that the data covers. Fortunately, the data analysis application is package aware. It recognises the rel=package link and automatically downloads the package, which looks like:

Content-Type: application/package
Link: <datapackage.json>; rel=describedby

Content-Location: datapackage.json
Content-Type: application/json

... machine-readable description of the package ...

Content-Location: imd.csv
Content-Type: text/csv

... statistical data ...

Content-Location: geographies.csv
Content-Type: text/csv

... data about the geographies covered by the statistics ...

Content-Location: imd.pdf
Content-Type: application/pdf

... human-readable documentation of the data ...


The data analysis application uses the information in datapackage.json to handle the types of the values in the original data correctly, and to display them with nice labels. It provides easy access to the linked information from geographies.csv and shows the data scientist the human-readable documentation that has been made available.


Package-aware data analysis software SHOULD follow rel=package links in HTTP headers to access additional information about data that it retrieves by HTTP.

Data publishers SHOULD use the Link header to provide packages of information when individual (context-free) data files are requested.

Streamable Package Format

This section defines the Streamable Package Format (SPF) which has the media type application/package.

The term streamable is used to denote that processing of package does not mandate keeping all individual parts in memory, both for creation and consumption of the package content.

SPF is designed to be consistent with multipart media types. However it is not defined as a multipart/* subtype because these types require the inclusion of a boundary parameter in their media type. Setting this parameter is burdensome in situations when the publisher is not able to configure the server. It is also unnecessary as the boundary can be ascertained from the content of the file.

An example SPF file is as follows:

Content-Location: /index.html
Content-Type: text/html

    <script src="/scripts/app.js"></script>

Content-Location: /scripts/app.js
Content-Type: text/javascript

module Math from '/scripts/helpers/math.js';

Content-Location: /scripts/helpers/math.js
Content-Type: text/javascript

export function sum(nums) { ... }


This SPF file includes three parts/index.html, /scripts/app.js and /scripts/helpers/math.js — and uses the boundary gc0pJq0M:08jU534c0p.

The general structure of an SPF file is described by the following [[!ABNF]]:

spf  = [ header CRLF ]
       1*( part CRLF )
       "--" boundary "--"

header = *( message-header CRLF )

part = "--" boundary CRLF
       *( message-header CRLF )
       [ message-body ]

Package Header

Should a package include a header for itself? Should it be in the same message-header format as is used elsewhere? This is flexible if somewhat verbose, and enables us to lean on well-known existing methods of expressing metadata rather than inventing a custom format.

An SPF file MAY start with an optional package header that provides metadata about the package itself. The syntax of this header is the same as that of the header within each part of the package. See for details.

An example package that includes a package header is shown below.

Content-Type: application/package
Link: <config.xml>; rel=describedby

Content-Location: config.xml
Content-Type: application/xml

<?xml version="1.0" encoding="UTF-8"?>
<widget xmlns       = ""
        id          = ""
        version     = "2.0 Beta"
        height      = "200"
        width       = "200"
        viewmodes   = "fullscreen">
... other parts ...

The package metadata explicitly:


A package file is comprised of a number of parts, separated by boundaries. Each part comprises a header and a body.

In ABNF, the definition of message-header and of message-body are taken from [[RFC2616]] and are:

  message-header = field-name ":" [ field-value ]
  field-name     = token
  field-value    = *( field-content | LWS )
  field-content  = <the OCTETs making up the field-value
                   and consisting of either *TEXT or combinations
                   of token, separators, and quoted-string>

  message-body   = entity-body
                   | <entity-body encoded as per Transfer-Encoding>
  entity-body    = *OCTET

The body of a part can be any binary data. It MUST NOT include the boundary used in the package.

The header of a part follows the same syntax as the header for an HTTP response, and can reuse any HTTP header. This header MUST include a Content-Location header which provides the part URL. The URL provided by the Content-Location header MUST be a relative URL and MUST NOT be a scheme-relative URL. The URL is resolved using a base URL that is the location of the package. Other URLs used within the part header (for example in Link headers) or in the body of the part (for example within src attributes if the part is an HTML document) MUST be resolved using the part URL as the base URL.

Applications that process packages SHOULD ignore parts which do not have a Content-Location header, or whose Content-Location header is not a relative URL or is a scheme-relative URL. Such parts contain information about resources from a different origin than the package itself, which might not be trustworthy.

It is possible for multiple parts within a package to have the same part URL, either because they have exactly the same Content-Location header or because their Content-Location headers resolve to the same URL. Parts with the same part URL SHOULD be distinguishable by having different values for other headers commonly used for content negotiation, such as Accept or Accept-Language. When these headers are used to distinguish between parts, they SHOULD be listed within the Vary header for the parts that share the same part URL. For example:

--r 87q0ewahn8o9fqrt0cadkm
Content-Location: /events/extensible-web-summit-2014
Content-Type: text/html
Vary: Accept

... HTML page about the Extensible Web Summit 2014 ...

--r 87q0ewahn8o9fqrt0cadkm
Content-Location: /events/extensible-web-summit-2014
Content-Type: text/calendar
Vary: Accept

... iCalendar event for the Extensible Web Summit 2014 ...

--r 87q0ewahn8o9fqrt0cadkm--

When a part is itself a Streamable Package Format package, its package header should become the part header. For example:


Content-Location: brand/main.css
Content-Type: text/css
Link: <brand/font.pack>; rel=package; scope=brand/font/

@font-face {
  font-family: 'BrandFont';
  src: url('font/brand.woff') format('woff')
       url('font/brand.ttf') format('truetype');
... rest of the CSS ...

Content-Location: brand/font.pack
Content-Type: application/package

Content-Location: font/brand.woff
Content-Type: application/font-woff

... font in WOFF format ...

Content-Location: font/brand.ttf
Content-Type: application/font-sfnt

... font in Truetype format ...



A boundary is used to separate the parts within the package. The same boundary is used throughout the package. The boundary used within an SPF file MUST NOT appear within the body of any part in the package. The boundary can be identified by an application by taking the string after the initial "--" of the first line that starts with a "--".

The definition of boundary is taken from [[RFC2046]] and is:

boundary      = 0*69bchars bcharsnospace

bchars        = bcharsnospace / " "

bcharsnospace = DIGIT / ALPHA / "'" / "(" / ")" /
                "+" / "_" / "," / "-" / "." /
                "/" / ":" / "=" / "?"

Note that this places the restriction on the boundary that it must not be more than 70 characters long and it cannot end in a space character.

Fragment Identifiers

The fragment identifier scheme for the application/package media type can be used to identify a part of the package or a fragment of a part.

In general, links should be made directly to resources on the web rather than to parts of packages. The particular package(s) that a resource appears in may be an ephemeral phenomenon.

The general syntax of a fragment identifier for Streamable Package Format documents is one or more param=value pairs, separated by semi-colons. In ABNF:

fragment      = parameter *( ";" parameter )
parameter     = ( "url" "=" value )
              / ( "rel" "=" relation-type )
              / ( "type" "=" ( media-type / quoted-mt ) )
              / ( "lang" "=" Language-Tag )
              / ( "fragment" "=" value )

value         = quoted-string / string-no-sc
quoted-string = < as defined in [RFC2616] >
string-no-sc  = < any string that does not contain a semicolon >
relation-type = < as defined in [RFC5988] >
media-type    = < as defined in [RFC5988] >
quoted-mt     = < as defined in [RFC5988] >
Language-Tag  = < as defined in [RFC5646] >

Note that when used within a URL, some characters within the fragment identifier, such as #, should be escaped.

The fragment identifier MUST contain either a url parameter or a rel parameter and MUST NOT contain both of these parameters. These parameters are used to construct an initial list of candidate parts as follows:

  1. If the url parameter is specified, this is interpreted as a (possibly quoted) URL that is resolved relative to the base URL of the package to create a candidate parts URL. The candidate parts are those parts whose part URL is equal to the candidate parts URL.
  2. If the rel parameter is specified, the package header is examined for Link headers whose rel parameter is equal to the rel parameter of the fragment identifier. There may be several such Link headers, which are used to create a list of candidate part URLs by resolving the target URL of each link against the base URL of the package. The candidate parts are those parts whose part URL is equal to any of the candidate part URLs.

If the type or lang parameters are specified in the fragment identifier, these are used to further narrow down the candidate parts:

  1. If the type parameter is specified, the candidate parts are filtered down to only those that have a Content-Type header whose media type matches the (possibly quoted) media type provided by the type parameter.
  2. If the lang parameter is specified, the candidate parts are further filtered down to only those that have a Content-Language header whose media type matches the language tag provided by the lang parameter.

If there are no parts in the list of candidate parts then the fragment identifier does not identify any fragment of the package. Otherwise, the identified part is the first part within the list of candidate parts.

If the fragment identifier specifies a fragment parameter, the value of that parameter is used to identify a fragment within the identified part, according to the media type for that part (as given by its Content-Type header).

For example, the URL:;fragment=colophon

refers to an element whose id is colophon within the part of the package whose part URL is This should be the same as:

As an example of using the rel and type parameters, imagine a package like:

Link: </metadata/spending>; rel=describedby

Content-Location: /metadata/spending
Content-Type: text/turtle
Vary: Accept

... Metadata about the package in Turtle format ...

Content-Location: /metadata/spending
Content-Type: application/ld+json
Vary: Accept

... Metadata about the package in JSON-LD format ...


The URL:;type=application/ld+json

would identify the second of the parts in the package. The rel=describedby in the fragment identifier indicates that the target URL of the Link header should be used to locate the relevant part. Since there are two parts whose part URL is, the type=application/ld+json parameter is used to narrow the selection down to the second of the parts, whose Content-Type header matches.

Security Considerations

As it contains other files, Streamable Package Format files may contain active content (such as scripts) which, if run, may have devastating effects. Applications should treat all files contained within a package with the same care as they would if they had been received individually.

Packages in the Streamable Package Format contain assertions about the content of resources at other locations on the web (indicated through the part URL). Applications that process files in the Streamable Package Format should be aware that the content might not match that at the part URL. discusses the implications of this when packages are used to populate caches.

Creating and Publishing Packages

This section contains some recommendations and guidelines for the creation of packages in the Streamable Package Format.


Packages may be compressed in their entirety or the individual parts of the package may be compressed independently. In the latter case, the part headers should indicate the compression algorithm that has been used on the part during the packaging process using a Transfer-Encoding header.

Not sure what to recommend here. Presumably compressing the entire file undermines its streamability so the recommendation should be to compress individual parts?

Part Ordering

The first part in a package should usually provide a starting point for understanding or making use of the other resources in the package. For example, it might be:

  • a manifest file
  • the root page for a web application
  • the Javascript file into which the others are imported
  • the table of contents of a digital publication
  • the page that was the initial page crawled when creating a web archive

The remaining parts should be ordered based on the priority with which they need to be loaded to enable the contents of the package to be used (with high priority parts earlier in the package), and based on the size of the part (with larger parts later in the package). For a web application, a suitable order might be:

  1. the root page of the web application
  2. set-up scripts & data
  3. stylesheets
  4. fonts
  5. logo & background images
  6. deferred scripts
  7. content images
  8. secondary HTML pages
  9. other resources used only on those HTML pages

Part Headers

As described in , you can provide any HTTP header for the parts within a package and must provide a Content-Location header. Some HTTP headers are inappropriate because the part is not, in fact, an HTTP response. Other HTTP headers that may be useful for applications are:

package Link Relation

The package link relation refers to a package in which a representation of the link's context URL or related resources can be found. There are no constraints on the format of the package (the package may be a zip, or any of the other package formats listed in , for example).

Would it be helpful to distinguish between a package in which the link's context resource itself can be found, and one which only contains related resources?

The package link relation can be used wherever link relations can be used, such as in links within web pages:

<a href="editor.gzip" rel="package">download this application</a>

or links within the header of an HTML page:

<link rel="package" href="" type="application/widget">

or links within an HTTP header:

Link: </downloads/spending.pack>; rel=package; type=application/package

Package Scope

When referring to a package, it is often useful to provide an indication of what the package contains so that an application retrieving the package can anticipate which resources it can get from the package rather than directly. This can be indicated by specifying a package scope, which is a URL. Applications can use this as a hint that indicates that any resources whose URL starts with the package scope can be found within the package. If no package scope is indicated in a link, applications MUST NOT make any assumptions about the contents of the package.

In an HTML document, the package scope is indicated through a scope attribute on the <a> or <link> element that references the package. This attribute contains a URL that is resolved against the base URL of the HTML document. For example:

<a href="editor.gzip" rel="package" scope="/">download this application</a>

indicates that the entire website that includes the page in which this link is found is contained within the package, while:

<link rel="package" href="" type="application/widget" scope="">

indicates that any resources whose URLs start with can be found within

In an HTTP Link header, the package scope is indicated through a scope link extension. The value of this link extension has the same syntax and is resolved in the same way as the anchor parameter as defined in [[!RFC5988]]. (In summary, it is a URL wrapped in double quotes, which is resolved against the requested URL.)

For example if the response to a request to includes the header:

Link: </downloads/spending.pack>; rel=package; type=application/package; scope="spending-"

this implies that the package at contains all resources whose URL begins with (including the requested

IANA Considerations

application/package Media Type Registration

This registration is for community review and will be submitted to the IESG for review, approval, and registration with IANA within the media type registry in accordance with [[RFC6838]].

Type name:
Subtype name:
Required parameters:
Optional parameters:
Encoding considerations:
Security considerations:
Interoperability considerations:
Published specification:
this document
Applications that use this media type:
no specific applications
Fragment identifier considerations:
Additional information:
Deprecated alias names for this type:
Magic number(s):
File extension(s):
Macintosh file type code(s):
Person & email address to contact for further information:
Jeni Tennison <>
Intended usage:
Restrictions on usage:
Jeni Tennison
Change controller:

package Link Relation Registration

This registration is for community review and will be submitted to the IESG for review, approval, and registration with IANA within the Registry of Link Relations in accordance with [[RFC5988]].

Relation name:
Refers to a package in which a representation of the link's context or related resources can be found.
this document