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.

Status of This Document

This section describes the status of this document at the time of its publication. Other documents may supersede this document. A list of current W3C publications and the latest revision of this technical report can be found in the W3C technical reports index at http://www.w3.org/TR/.

The Technical Architecture Group (TAG) has discontinued work on this document. The specification should not be referenced in this form or implemented as-is.

Please consult the WICG WebPackage repository for continuing work on this subject.

This document was published by the Technical Architecture Group as a Working Group Note. Comments regarding this document are welcome. Please send them to www-tag@w3.org (subscribe, archives).

Publication as a Working Group Note does not imply endorsement by the W3C Membership. This is a draft document and may be updated, replaced or obsoleted by other documents at any time. It is inappropriate to cite this document as other than work in progress.

This document was produced by a group operating under the W3C Patent Policy. W3C maintains a public list of any patent disclosures made in connection with the deliverables of the group; that page also includes instructions for disclosing a patent. An individual who has actual knowledge of a patent which the individual believes contains Essential Claim(s) must disclose the information in accordance with section 6 of the W3C Patent Policy.

This document is governed by the 1 March 2017 W3C Process Document.

Table of Contents

1. Introduction

Today's websites rely on multiple files. If a user visits http://www.bbc.co.uk/ they will need to download about 160 files to view the page in its entirety. The HTML page they download at http://www.bbc.co.uk/ 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 section 3. Streamable Package Format. It defines a package link relation to point to packages from other resources in section 4. package Link Relation. But first, in section 2. Using Packages, this document describes patterns of use for packages that address the requirements described in this introduction.

2. Using Packages

This section is non-normative.

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

2.1 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.

2.1.1 Example Scenario

In this scenario, a browser is pointed at the page http://example.org/shop which returns the HTML:

Example 1
    <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 section 4. package Link Relation) 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 section 4.1 Package Scope).

When the browser comes to download the resource http://example.org/lib/brand/style.css, it checks to see if that resource is included in the scope of a package. In this case, the URL starts with http://example.org/lib/brand/ so the browser can guess that it is included in the http://example.org/lib/brand.pack package and not make a separate request for the stylesheet.

The http://example.org/lib/brand.pack package contains the main CSS stylesheet, but also font files and images that are used as background images within the CSS:

Example 2
Content-Location: http://example.org/lib/brand.pack
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 http://example.org/lib/brand/main.css, http://example.org/lib/brand/shop.woff and http://example.org/lib/brand/images/bg.jpg. 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 http://example.org/lib/brand/main.css 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.

Issue 1

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.

2.1.2 Guidelines

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 section 4. package Link Relation.

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 section 3. Streamable Package Format), 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.

2.2 Installing Web Applications

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

2.2.1 Example Scenario

In this scenario, a browser is pointed at https://editor.example.com/. It fetches the home page of the site, and sees:

Example 3
    <link rel="package" href="/editor.zip" 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.

2.2.2 Guidelines

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 section 4. package Link Relation.

If a package is in the Streamable Package Format (described in section 3. Streamable Package Format), 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.

2.3 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.

2.3.1 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, https://example.org/time.pack. The package management system retrieves the package:

Example 4
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:

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

2.3.2 Guidelines

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.

2.4 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.

2.4.1 Example Scenario

An online news report references some recent demographic statistics, pointing to http://example.org/stats/imd.csv. 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:

Example 6
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:

Example 7
Content-Location: http://example.org/stats/imd.pack
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.

2.4.2 Guidelines

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.

3. Streamable Package Format

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


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:

Example 8
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 ]

3.1 Package Header

Issue 2

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 section 3.2 Parts for details.

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

Example 9
Content-Type: application/package
Content-Location: http://example.org/exampleWidget.pack
Link: <config.xml>; rel=describedby

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

<?xml version="1.0" encoding="UTF-8"?>
<widget xmlns       = "http://www.w3.org/ns/widgets"
        id          = "http://example.org/exampleWidget"
        version     = "2.0 Beta"
        height      = "200"
        width       = "200"
        viewmodes   = "fullscreen">
... other parts ...

The package metadata explicitly:

3.2 Parts

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 Content-Type or Content-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:

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

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

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

... 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:

Example 11
Content-Location: http://example.org/brand.pack

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 ...


3.3 Boundaries

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.

3.4 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:

Example 12

refers to an element whose id is colophon within the part of the package whose part URL is http://example.org/root.html. This should be the same as:

Example 13

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

Example 14
Content-Location: http://example.org/downloads/spending.pack
Link: </metadata/spending>; rel=describedby

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

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

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

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


The URL:

Example 15

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 http://example.org/metadata/spending, the type=application/ld+json parameter is used to narrow the selection down to the second of the parts, whose Content-Type header matches.

3.5 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. section 2.1 Populating Caches discusses the implications of this when packages are used to populate caches.

3.6 Creating and Publishing Packages

This section is non-normative.

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

3.6.1 Compression

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.

Issue 3

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

3.6.2 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

3.6.3 Part Headers

As described in section 3.2 Parts, 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:

5. IANA Considerations

5.1 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:
See section 3.5 Security Considerations
Interoperability considerations:
Published specification:
this document
Applications that use this media type:
no specific applications
Fragment identifier considerations:
See section 3.4 Fragment Identifiers
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 <jeni@theodi.org>
Intended usage:
Restrictions on usage:
Jeni Tennison
Change controller:

A. References

A.1 Normative references

D. Crocker, Ed.; P. Overell. Augmented BNF for Syntax Specifications: ABNF. January 2008. Internet Standard. URL: https://tools.ietf.org/html/rfc5234
M. Nottingham. Web Linking. October 2010. Proposed Standard. URL: https://tools.ietf.org/html/rfc5988

A.2 Informative references

Allen Wirfs-Brock. ECMA-262 ECMAScript Language Specification, Edition 6. Draft. URL: http://people.mozilla.org/~jorendorff/es6-draft.html
N. Freed; N. Borenstein. Multipurpose Internet Mail Extensions (MIME) Part Two: Media Types. November 1996. Draft Standard. URL: https://tools.ietf.org/html/rfc2046
R. Fielding; J. Gettys; J. Mogul; H. Frystyk; L. Masinter; P. Leach; T. Berners-Lee. Hypertext Transfer Protocol -- HTTP/1.1. June 1999. Draft Standard. URL: https://tools.ietf.org/html/rfc2616
N. Freed; J. Klensin; T. Hansen. Media Type Specifications and Registration Procedures. January 2013. Best Current Practice. URL: https://tools.ietf.org/html/rfc6838
Dimitri Glazkov; Hayato Ito. Introduction to Web Components. 24 July 2014. W3C Note. URL: http://www.w3.org/TR/components-intro/